2011-09-24 50 views
9

我原本以爲這可能與gnuplot - start of X series - Stack Overflow相同 - 但我認爲這是稍微更具體的。因爲我有興趣找到「X系列的開始」,可以這麼說 - 我會試着用一個例子來闡明;說你有這個腳本:將數據集值讀入gnuplot變量(X系列的開始)

# 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 

如果您繪製它,你會發現將數據從10開始於x軸:

gnuplot-startx.png

現在,當然你也可以調整xrange - 但有時候你對「從0開始」的「相對位置」感興趣,可以這麼說。因此,人們希望看到的數據「向左移動」在x軸上,所以它從0開始。因爲我們知道,在10.0的數據開始,我們可以減去從第一列明確:

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

...基本上就是這樣做的。

但是說你想在上面的plot命令來指定「10.0」明確;那麼 - 知道它是已經加載的數據的第一列的第一個元素,人們希望有一種方式來以某種方式在變量中讀取這個值 - 比如說,像下面的僞代碼那樣:

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

...和類似的東西,人們不必指定這個「x偏移」值,可以說,手動繪圖命令。

所以 - 重新表述 - 是否有一種方法可以讀取x系列的開始(數據集中給定列的第一個值)作爲gnuplot中的變量?

回答

6

兩種方式:

1. 繪製函數首先,讓gnup很多事要告訴最小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. 使用外部腳本要弄清楚什麼是最低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

太棒了 - 非常感謝你的簡潔的回答,@Sunhwan Jo - 乾杯! – sdaau

+0

是的,但是,如果您對數據序列中的* first *元素感興趣,但不一定需要最小值? – TMOTTM

+0

@TMOTTM,那麼你必須調整外部腳本來使用第一個元素(直接使用awk而不用排序部分)。 – EverythingRightPlace

2

嗯......好吧,我得到的東西:

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

...但是這看起來更像是「捕獲」的變量,比讀它(作爲函數initer被用來掃描數字流,檢測到第一個,並返回其值):)希望有這樣做的更好的辦法....

3

OK,我繼續回來這一點 - 因此,我認爲我需要在這裏作出以下澄清:

鑑於gnuplot,嗯,繪製數據集作爲二維圖 - 它給出它以某種方式處理2D結構或數組。這就是爲什麼有人來自C,Perl,Python等。自然會認爲可以以某種方式索引數據集,並且能夠在給定的行和列位置檢索一個值;說,像下面的僞代碼:

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

或者交替,僞代碼:
my_dataset = parse_dataset("inline.dat")
my_val = get_value(my_dataset, 1, 2)

,我花了很多時間尋找gnuplot這樣的事情,並不能找到類似的東西(通過行和列索引直接變量訪問數據集值)。看來只有可以做的事情,是plot數據集 - 並可能通過在using部分中調用的函數訪問值。

這意味着,如果我想找到gnuplot一些數據集的價值,我通過調用plot通過DataSet迭代 - 即使我需要這些值精確構造正確plot聲明:)我有種不喜歡的是,以爲第一plot可能以某種事後:)搞砸了第二然而,隨着finding maximum value in a data set and subtracting from plot - comp.graphics.apps.gnuplot | Google Groups指出,一個可以plot到一個文件中,也stdout/dev/null,並得到一個純ASCII格式的表格 - 所以至少我可以以這種方式重定向第一個電話,所以它不會干擾該行爲第二次打電話給plot

所以,下面是另一個代碼例如,當在「inline.dat」數據集的第一列的第一元件經由檢索到:

# 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 

...所以那麼情節可以通過直接first在偏移撥打plot

注意再次證明print_dataset_row_column電話plot(通過set table/dev/null重定向) - 正因爲如此,每次時間調用它來檢索值,就會引起反覆通過整個數據集!所以如果你需要第一個元素和最後一個元素(可能還有其他東西,比如some basic statistics with gnuplot),最好重寫print_dataset_row_column,以便一次檢索所有這些元素。

也是print_dataset_row_column如果您在數據集和using行中使用某些特殊格式,則需要重寫。請注意,在本例中,第三列是一個字符串 - 默認情況下,該字符串不會被接受爲繪圖數據列;因此,如果他們必須處理它,則調用print_dataset_*函數將失敗(另請參閱gnuplot plot from string)。

 

因此,這裏的示例代碼 - 姑且稱之爲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 

當這個腳本調用,在OP數據集繪製移動,從0開始 - 和以下在終端輸出(前幾個表格打印輸出從plot實際輸出經由set table重定向到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

從數據文件中讀取的單個值考慮以下用戶定義的函數:

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) 

當然,輸入到AWK具有忽略/無效的輸入(空行,註釋等)的被清除。例如:

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

但是,此功能將不允許讀取任何數據集,它僅限於文件。

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)) 

好點的定義這樣一個結:但是,這種限制可以通過檢查文件名參數的重定向字符「<」,並以一種合理的方式取代它(見三元運算符)來克服可能是你的.gnuplot init文件。

+0

感謝你們,@Hannes - 記住方便的方法。乾杯! – sdaau