2011-09-24 18 views
9

Originalmente pensé que podría ser el mismo que gnuplot - start of X series - Stack Overflow, pero creo que esto es un poco más específico.Lectura del valor del conjunto de datos en una variable gnuplot (inicio de la serie X)

Dado que estoy interesado en encontrar el "inicio de la serie X", por así decirlo, trataré de aclararlo con un ejemplo; supongamos que tiene este script:

# generate data 
system "cat > ./inline.dat <<EOF\n\ 
10.0 1 a 2\n\ 
10.2 2 b 2\n\ 
10.4 3 a 2\n\ 
10.6 4 b 2\n\ 
10.8 5 c 7\n\ 
11.0 5 c 7\n\ 
EOF\n" 

# ranges 
set yrange [0:8] 
set xrange [0:11.5] 

plot "inline.dat" using 1:2 with impulses linewidth 2 

Si traza ella, se dará cuenta de que los datos se inicia desde 10 en el eje x:

gnuplot-startx.png

Ahora, por supuesto, se puede ajustar el xrange - pero a veces le interesan las "posiciones relativas" que comienzan "desde 0", por así decirlo. Por lo tanto, a uno le gustaría ver los datos "movido hacia la izquierda" en el eje x, por lo que comienza a 0. Como sabemos los datos comienza en 10,0, podríamos restar que a partir de la primera columna de forma explícita:

plot "inline.dat" using ($1-10.0):2 with impulses linewidth 2 

... y eso básicamente hace el truco.

Pero digo no quiere especificar el "10.0" explícitamente en el plot comando de arriba; entonces, sabiendo que es el primer elemento de la primera columna de datos que ya está cargado, uno esperaría que haya una manera de leer este valor en una variable, por ejemplo, con algo parecido al pseudocódigo siguiente:

varval = "inline.dat"(1,1) # get first element of first column in variable 
plot "inline.dat" using ($1-varval):2 with impulses linewidth 2 

... y con algo como esto, uno no tendría que especificar este valor de "x desplazamiento", por así decirlo, manualmente en el comando de trazado.

Entonces, para reformular, ¿hay alguna manera de leer el inicio de la serie x (el primer valor de una columna dada en un conjunto de datos) como una variable en gnuplot?

Respuesta

6

dos maneras:

1. trazar la función primera y dejar gnup mucho que diga el valor mínimo x:

plot "inline.dat" using 1:2 with impulses linewidth 2 

xmin = GPVAL_DATA_X_MIN 
plot "inline.dat" using ($1-xmin):2 with impulses linewidth 2 

2. uso de script externo para averiguar cuál es el valor mínimo de x:

xmin = `sort -nk 1 inline.dat | head -n 1 | awk '{print $1}'` 
plot "inline.dat" using ($1-xmin):2 with impulses linewidth 2 
+0

Impresionante - muchas gracias por la respuesta concisa, @Sunhwan Jo - ¡Salud! – sdaau

+0

sí, PERO, ¿y si está interesado en el * primer * elemento de la serie de datos, que no necesariamente tiene que ser el mínimo? – TMOTTM

+0

@TMOTTM luego tiene que ajustar el script externo para usar solo el primer elemento (usando awk directamente sin la parte de clasificación). – EverythingRightPlace

2

Hmmm ... OK, tengo algo:

initer(x) = (!exists("first")) ? first = x : first ; 
plot "inline.dat" using ($1-initer($1)):2 with impulses linewidth 2 

... pero esto se parece más a "capturar" una variable, que leerlo (como la función initer está siendo utilizado para escanear una serie de números, detectar la primera, y devolver su valor) :) Espero que hay una mejor manera de hacer esto ....

3

bien, sigo volviendo a esto - así que creo Necesitaba la siguiente aclaración aquí:

Dado que gnuplot, bueno, traza conjuntos de datos como trazados 2D, es un hecho que de alguna manera se ocupa de estructuras 2D o matrices. Es por eso que alguien viene de C, Perl, Python, etc.pensaría naturalmente que es posible indexar de alguna manera el conjunto de datos, y ser capaz de recuperar un valor en una fila y posición de columna; decir, algo así como lo siguiente pseudocódigo:

my_val = "inline.dat"[1][2]  # get value in 1st row and 2nd column 

O, alternativamente, pseudocódigo:
my_dataset = parse_dataset("inline.dat")
my_val = get_value(my_dataset, 1, 2)

Y pasé un montón de tiempo buscando algo como esto en gnuplot, y no puede encuentre algo así (un acceso variable directo a los valores del conjunto de datos a través del índice de fila y columna). Parece que el único que uno puede hacer, es plot el conjunto de datos - y posiblemente acceda a los valores allí, a través de la función llamada en la parte using.

Eso quiere decir, que si quiero encontrar algunos valores del conjunto de datos de gnuplot, me tengo para recorrer el conjunto de datos llamando plot - incluso si necesito esos valores, precisamente para construir una adecuada plot comunicado :) Y que tipo de mesa no les gusta que, pensando que la primera plot puede de alguna manera tornillo hasta el segundo después :) Sin embargo, como finding maximum value in a data set and subtracting from plot - comp.graphics.apps.gnuplot | Google Groups puntos, uno puedeplot a un archivo, también stdout o /dev/null, y obtener un plano ASCII formateado - así al menos lo que pueda redirigir la primera llamada de esa manera, para que no interfiera con el acto terminal de trazado de la segunda llamada al plot.

Por lo tanto, a continuación es otro ejemplo de código, donde el primer elemento de la primera columna en el conjunto de datos "inline.dat" se recupera a través de:

# print and get (in _drcv) first value of first data column: 
eval print_dataset_row_column("inline.dat",0,1) 

# must "copy" the "return" value manually: 
first = _drcv 

... por lo que entonces la trama puede ser compensado por first directamente la llamada plot.

Nota vez más que print_dataset_row_column llamadas plot (redireccionados vía set table a /dev/null) - y, como tal, cada vez que la llame para recuperar un único valor , que hará que la iteración a través de la totalidad de conjunto de datos! Por lo tanto, si necesita el primer elemento y el último elemento (y posiblemente otros elementos, como some basic statistics with gnuplot), probablemente sea mejor volver a escribir print_dataset_row_column para que recupere todos los elementos de una vez.

También sería necesaria una reescritura print_dataset_row_column si utiliza algunos formatos especiales en su conjunto de datos y la línea using. Tenga en cuenta que en este ejemplo, la tercera columna es una cadena, que no se acepta de forma predeterminada como una columna de datos de trazado; y como tal, las llamadas a las funciones print_dataset_* fallarán si tienen que tratar con ellas (vea también gnuplot plot from string).

 

Así que aquí es el código de ejemplo - vamos a llamarlo test.gp:

# generate data 
system "cat > ./inline.dat <<EOF\n\ 
10.0 1 a 2\n\ 
10.2 2 b 2\n\ 
10.4 3 a 2\n\ 
10.6 4 b 2\n\ 
10.8 5 c 7\n\ 
11.0 5 c 7\n\ 
EOF\n" 

### "dry-run" functions: 
# iterate through dataset by calling 
# `plot`, redirected to file output (via `set table`) 
# 
# note: eval (not print) cannot be inside a user-defined function: 
# a(b) = eval('c=3') ; print a(4) ==> "undefined function: eval" 
# nor you can make multistatement functions with semicolon: 
# f(x) = (2*x ; x=x+2) ==> ')' expected (at ';') 
# 
# so these functions are defined as strings - and called through eval 
# 
# through a single column spec in `using`: 
# (`plot` prints table to stdout) 
# 
print_dataset_column(filename,col) = "set table '/dev/stdout' ;\ 
plot '".filename."' using ".col." ;\ 
unset table" 
# 
# through two column spec in `using`: 
# (`plot` prints table to stdout) 
# 
print_dataset_twocolumn(filename,colA,colB) = "set table '/dev/stdout' ;\ 
plot '".filename."' using ".colA.":".colB." ;\ 
unset table" 
# 
# print value of row:column in dataset, saving it as _drcv variable 
# 
# init variable 
# 
_drcv = 0 
# 
# create _drc helper function; note assign and "return" in 
# true branch of ternary clause 
# 
_drc(ri, colval, col) = (ri == _row) ? _drcv = colval : colval 
# 
# define the callable function: 
# 
print_dataset_row_column(filename,row,col) = "_row = ".row." ;\ 
set table '/dev/null' ;\ 
plot '".filename."' using (_drc($0, $".col.", ".col.")) ;\ 
unset table ;\ 
print '".filename."[r:".row.",c:".col."] = ',_drcv" 
# 
# 
### end dry run functions 


# 
# test print_dataset_* functions: 
# 

eval print_dataset_column("inline.dat",0) 
eval print_dataset_twocolumn("inline.dat",0,0) 

# string column - cannot directly: 
# set table '/dev/stdout' ;plot 'inline.dat' using 3 ;unset table 
#            ^
# line 69: warning: Skipping data file with no valid points 
# line 69: x range is invalid 
#~ eval print_dataset_column("inline.dat",3) 

eval print_dataset_column("inline.dat",1) 
eval print_dataset_twocolumn("inline.dat",1,2) 

eval print_dataset_row_column("inline.dat",4,1) 
eval print_dataset_row_column("inline.dat",4,2) 

# will fail - 3 is string column 
# line 82: warning: Skipping data file with no valid points 
# line 82: x range is invalid 
#~ eval print_dataset_row_column("inline.dat",4,3) 


# 
# do a plot offset by first element position 
# 

# print and get (in _drcv) first value of first data column: 
eval print_dataset_row_column("inline.dat",0,1) 
# must "copy" the "return" value manually: 
first = _drcv 

# ranges 
set yrange [0:8] 
set xrange [0:11.5] 

# plot finally: 
plot "inline.dat" using ($1-first):2 with impulses linewidth 2 

Cuando este script se llama, el conjunto de datos en el OP se traza trasladó, a partir de 0 - y la siguiente se emite en terminal (las primeras impresiones de la tabla son la salida real de plot redirigido a través de set table a stdout):

gnuplot> load './test.gp' 

# Curve 0 of 1, 6 points 
# Curve title: "'inline.dat' using 0" 
# x y type 
0 0 i 
1 1 i 
2 2 i 
3 3 i 
4 4 i 
5 5 i 


# Curve 0 of 1, 6 points 
# Curve title: "'inline.dat' using 0:0" 
# x y type 
0 0 i 
1 1 i 
2 2 i 
3 3 i 
4 4 i 
5 5 i 


# Curve 0 of 1, 6 points 
# Curve title: "'inline.dat' using 1" 
# x y type 
0 10 i 
1 10.2 i 
2 10.4 i 
3 10.6 i 
4 10.8 i 
5 11 i 


# Curve 0 of 1, 6 points 
# Curve title: "'inline.dat' using 1:2" 
# x y type 
10 1 i 
10.2 2 i 
10.4 3 i 
10.6 4 i 
10.8 5 i 
11 5 i 

inline.dat[r:4,c:1] = 10.8 
inline.dat[r:4,c:2] = 5.0 
inline.dat[r:0,c:1] = 10.0 
3

para leer un valor único de un archivos de datos de considerar el siguiente usuario función definida:

at(file, row, col) = system(sprintf("awk -v row=%d -v col=%d 'NR == row {print $col}' %s", row, col, file)) 
file="delta-fps" ; row=2 ; col=2 
print at(file,row,col) 

Por supuesto, la entrada a awk tiene que ser limpiado de entrada ignorado/inválido (líneas en blanco, comentarios, etc.) . Por ejemplo:

at(file, row, col) = system(sprintf("grep -v '^#|^$' %s | awk -v row=%d -v col=%d 'NR == row {print $col}'", file, row, col)) 

Sin embargo, esta función no permitirá la lectura de cualquier conjunto de datos, se limita a los archivos. Sin embargo, esta limitación puede ser superada mediante la comprobación del carácter redirección '<' en el argumento de nombre de archivo y la sustitución de una forma sensible (ver el operador ternario):

at(file, row, col)=system(sprintf("%s | grep -v '^#\\|^$' | awk -v row=%d -v col=%d 'NR == row {print $col}'", (file[:1] eq '<') ? file[2:] :'cat '.file, row, col)) 

Un buen punto para definir una unción tal puede ser su archivo de inicio .gnuplot.

+0

Gracias por eso, @Hannes: enfoque práctico a tener en cuenta. ¡Aclamaciones! – sdaau

Cuestiones relacionadas