I tried to run the following Tcl script and got the error: wrong # args: should be "set varName ?newValue?"
What does this mean?
Note: The script includes terms specific to VMD program, such as mol and resid. Please disregard them.
#count water molecules between chain A and chain C or between #chain B and chain C
set input_file [open ./name_3_pdb_chain_renamed.dat r]
set data [read $input_file]
set data [split $data "\n"]
close $input_file
set chain_list [lindex $data 0]
cd 7_count_water
set outfile [open count_water3.dat w]
set chain_compare ""
set pdblen [llength $chain_list]
for {set i 0} {$i<$pdblen} {incr i} {
set pid [lindex [lindex $chain_list $i] 0]
set len [llength [lindex $chain_list $i]]
mol load pdb ../2_chain_rename/${pid}_chain_revised.pdb
mol modstyle 0 top NewCartoon
if {$len==4} {
set chain_compare [lappend chain_compare $pid]
}
set 11 [atomselect top all]
set mid [$11 molid]
mol delete $mid
}
set lll [llength $chain_compare]
for {set j 0} {$j< $lll} {incr j} {
set pid [lindex $chain_compare $j]
mol load pdb ../2_chain_rename/${pid}_chain_revised.pdb
set 11 [atomselect top "chain A and name CA"]
set res_len [llength [$11 get resid]]
set res_id [$11 get resid]
#residue length for chain C
set ag [atomselect top "chain C and name CA"]
set ag_len [llength [$ag get resid]]
set ag_id [$ag get resid]
#loop water between chain A and chain C
for {set k 0} {$k<$res_len} {incr k} {
set water_around_a [atomselect top "{resname HOH and {within 5.0 of {chain A and resid [lindex $res_id $k]} and {within 5.0 of chain C}}} "]
set water_around_a_resid [$water_around_a get resid]
set water_around_a_resname [$water_around_a get resname]
#loop antigen residues around water
for {set g 0} {$g < $ag_len} {incr g} {
set ag_around_water [atomselect top "{chain C and resid [lindex $ag_id $g] and {within 5.0 of {resname HOH and {within 5.0 of {chain A and resid [lindex $res_id $k]}}}}} "]
set ag_around_water resid [$ag_around_water get resid]
set ag_around_water_resname [$ag_around_water get resname]
puts $outfile "$pid [lindex $res_id $k] [lindex [$11 get resname] $k] $ag_around_water_resname A: $water_around_a_resname"
}
}
set b11 [atomselect top "chain B and name CA"]
set b_res_len [llength [$b11 get resid]]
set b_res_id [$b11 get resid]
#residue length for chain C
set ag [atomselect top "chain C and name CA"]
set ag_len [llength [$ag get resid]]
set ag_id [$ag get resid]
for {set k 0} {$k<$res_len} {incr k} {
set water_around_b [atomselect top "{resname HOH and {within 5.0 of {chain B and resid [lindex $b_res_id $k]} and {within 5.0 of chain C}}} "]
set water_around_b_resid [$water_around_b get resid]
set water_around_b_resname [$water_around_b get resname]
#loop antigen residues around water
for {set g 0} {$g < $ag_len} {incr g} {
set ag_around_water [atomselect top "{chain C and resid [lindex $ag_id $g] and {within 5.0 of {resname HOH and {within 5.0 of {chain B and resid [lindex $b_res_id $k]}}}}} "]
set ag_around_water resid [$ag_around_water get resid]
set ag_around_water_resname [$ag_around_water get resname]
puts $outfile "$pid [lindex $b_res_id $k] [lindex [$b11 get resname] $k] $ag_around_water_resname A: $water_around_b_resname"
}
}
}
close $outfile
cd ..
Thank you
That message:
wrong # args: should be "set varName ?newValue?"
is a standard error thrown when a built-in command gets the wrong number of arguments to evaluate. In this case, it's coming from the set command, and indicates that you've either said set on its own, or given more than two further arguments to it.
If you examine the stack trace (usually printed with the error message when using standard tclsh, though it's changeable with user code) then you'll get told where the problem happened. However, in this case we can look through and see that this line near the bottom of the script:
set ag_around_water resid [$ag_around_water get resid]
has what appears to be a space instead of an underscore in the variable name. Now, spaces are legal in variable names, but then the variable name needs to be quoted, and that can get a bit annoying. It's usually best to avoid using them like that. Without quoting, Tcl doesn't know that that's meant to be one word; the generic parsing layer decides there's really four words there (set, ag_around_water, resid and the complex [$ag_around_water get resid]) and tells set to deal with that, which it doesn't like.
Remember, Tcl's generic syntactic parsing happens first, before command arguments are interpreted semantically. Always.
The line set ag_around_water resid [$ag_around_water get resid] needs to be changed. You probably want ag_around_water_resid instead.
Related
I have a very large file that contains data like below:
*1 RES L1 N1 0.32
*22 RES L2 N2 0.64
*100 CAP A1 B1 0.3
*200 CAP A2 B1 0.11
*11 IND K1 K2 0.002
*44 IND X1 Y1 0.00134
... and so on
For such files (let us assume the above data is in a file called "example.txt"), I can easily create a Hash of Hashes in Perl and pass these nested Hashes to otherr parts of my Perl program:
#!/usr/bin/perl
use strict;
use warnings;
open(FILE,"<", "example.txt") or die "Cannot open file:$!";
if (-f "example.txt") {
while(<FILE>) {
chomp;
if(/^\s*(\S+)\s+(RES|CAP|IND)\s+(\S+)\s+(\S+)\s+(\S+)\s*$/) {
$hoh{$1}{$2}{$3}{$4} = $5;
}
}
close FILE;
}
What is a similar way to create a Tcl Hash of Hashes (or rather Dictionary of Dictionaries)?
I tried a small piece of code setting the dict like below (not printing the full code here, to keep focus on the problem):
...
set dod [dict create]
if [regexp {^\s*(\S+)\s+(RES|CAP|IND)\s+(\S+)\s+(\S+)\s+(\S+)\s*$} $line all id type x y elemValue] {
dict set dod $id $type $x $y $elemValue
}
But that does not seem to work. I tested it like below:
foreach id [dict keys $dod] {
if [dict exists $dod "RES"] {
puts "RES KEY EXISTS"
} else {
puts "RES KEY NOT FOUND"
}
}
Thanks.
Your immediate problem is a stray slash in the beginning of the regular expression.
To answer the question: a multi-key dictionary is a "hash of hashes". Every key adds a new level of dictionaries.
dict set foo aa bb cc 1
sets the member {cc 1} in a dictionary which is the value of the member {bb ...} in the dictionary which is the value of the member {aa ...} in foo.
If you don't want a multi-level dictionary and still need to use several key values, you need to do:
dict set foo [list aa bb cc] 1
Also, I don't know how much is simplified away in your example, but the code to add an item could be better stated as:
if {[lindex $line 1] in {RES CAP IND}} {
dict set dod {*}$line
}
But if you want to check existence by e.g. "RES", you need to set it as the top-level key, which you don't in your example (the items in the first column become top-level keys). Initializing as above, the value of dod is
*1 {RES {L1 {N1 0.32}}} *22 {RES {L2 {N2 0.64}}} *100 {CAP {A1 {B1 0.3}}} *200 {CAP {A2 {B1 0.11}}} *11 {IND {K1 {K2 0.002}}} *44 {IND {X1 {Y1 0.00134}}}
so you do get a dictionary, but dict exists $dod RES is still necessarily false. By using
if {[lindex $line 1] in {RES CAP IND}} {
dict set dod {*}[lrange $line 1 end]
}
(i.e. all the items in the line after the first as keys, except the last which becomes the value) you get the dictionary
RES {L1 {N1 0.32} L2 {N2 0.64}} CAP {A1 {B1 0.3} A2 {B1 0.11}} IND {K1 {K2 0.002} X1 {Y1 0.00134}}
in which you can test for the existence of "RES".
Going back to the dict-of-dicts
*1 {RES {L1 {N1 0.32}}} *22 {RES {L2 {N2 0.64}}} *100 {CAP {A1 {B1 0.3}}} *200 {CAP {A2 {B1 0.11}}} *11 {IND {K1 {K2 0.002}}} *44 {IND {X1 {Y1 0.00134}}}
you can check for "RES" by examining each of the sub-dictionaries until you find one that has that key:
set found 0
dict for {key subdict} $dod {
if {[dict exists $subdict RES]} {
set found 1
break
}
}
Documentation:
dict
Not exactly same but somewhat similar:
set data "*1 RES L1 N1 0.32
*22 RES L2 N2 0.64
*100 CAP A1 B1 0.3
*200 CAP A2 B1 0.11
*11 IND K1 K2 0.002
*44 IND X1 Y1 0.00134
"
set pattern {\s*(\S+)\s+(RES|CAP|IND)\s+(\S+)\s+(\S+)\s+(\S+)?\s*$}
set result [regexp -all -line -inline -- $pattern $data]
if {[llength $result] == 0} {
puts "Not found"
exit 1
}
array set my_data {}
foreach {all ind_0 ind_1 ind_2 ind_3 ind_4} $result {
set my_data($ind_0)($ind_1)($ind_2)($ind_3) $ind_4
}
puts [parray my_data]
Sample output:
my_data(*1)(RES)(L1)(N1) = 0.32
my_data(*100)(CAP)(A1)(B1) = 0.3
my_data(*11)(IND)(K1)(K2) = 0.002
my_data(*200)(CAP)(A2)(B1) = 0.11
my_data(*22)(RES)(L2)(N2) = 0.64
my_data(*44)(IND)(X1)(Y1) = 0.00134
I have some data that I want to plot them with gnuplot. But I have for the same x value many y values, I will show you to understand well:
0 0.650765 0.122225 0.013325
0 0.522575 0.001447 0.010718
0 0.576791 0.004277 0.104052
0 0.512327 0.002268 0.005430
0 0.530401 0.000000 0.036541
0 0.518333 0.001128 0.017270
20 0.512864 0.001111 0.005433
20 0.510357 0.005312 0.000000
20 0.526809 0.001089 0.033523
20 0.527076 0.000000 0.034215
20 0.507166 0.001131 0.000000
20 0.513868 0.001306 0.004344
40 0.531742 0.003295 0.0365
In this example, I have 6 values for each x value.So how can I draw the average and the confidence bar(interval) ??
thanks for help
To do this, you will need some kind of external processing. One possibility would be to use gawk to calculate the required quantities and the feed this auxiliary output to Gnuplot to plot it. For example:
set terminal png enhanced
set output 'test.png'
fName = 'data.dat'
plotCmd(col_num)=sprintf('< gawk -f analyze.awk -v col_num=%d %s', col_num, fName)
set format y '%0.2f'
set xr [-5:25]
plot \
plotCmd(2) u 1:2:3:4 w yerrorbars pt 3 lc rgb 'dark-red' t 'column 2'
This assumes that the script analyze.awk resides in the same directory from which Gnuplot is launched (otherwise, it would be necessary to modify the path in the -f option of gawk. The script analyze.awk itself reads:
function analyze(x, data){
n = 0;mean = 0;
val_min = 0;val_max = 0;
for(val in data){
n += 1;
delta = val - mean;
mean += delta/n;
val_min = (n == 1)?val:((val < val_min)?val:val_min);
val_max = (n == 1)?val:((val > val_max)?val:val_max);
}
if(n > 0){
print x, mean, val_min, val_max;
}
}
{
curr = $1;
yval = $(col_num);
if(NR==1 || prev != curr){
analyze(prev, data);
delete data;
prev = curr;
}
data[yval] = 1;
}
END{
analyze(curr, data);
}
It directly implements the online algorithm to calculate the mean and for each distinct value of x prints this mean as well as the min/max values.
In the Gnuplot script, the column of interest is then passed to the plotCmd function which prepares the command to be executed and the output of which will be plotted with u 1:2:3:4 w yerrorbars. This syntax means that the confidence interval is stored in the 3rd/4th columns while the value itself (the mean) resides in the second column.
In total, the two scripts above produce the picture below. The confidence interval on the last point is not visible since the example data in your question contain only one record for x=40, thus the min/max values coincide with the mean.
You can easily plot the average in this case:
plot "myfile.dat" using ($1):($2 + $3 + $4)/3
If you want average of only second and fourth column for example, you can write ($2+$4)/2 and so on.
Let's say that I have a Tcl dictionary. I want the fastest way to get the last entered key of the dict (not the value).
Theoretically, I could use:lindex [ dict keys $dict ] end Does anyone know anything else, which is faster?
This is pretty fast:
% set data {a 1 b 2 c 3}
a 1 b 2 c 3
% proc p1 {} {dict get $::data [lindex [dict keys $::data] end]}
% time {p1} 100000
1.87782 microseconds per iteration
But you can shave off about a microsecond by remembering the last key:
oo::object create mydict
oo::objdefine mydict {
variable data last
method add args {
lappend data {*}$args
set last [lindex [dict keys $data] end]
}
method getLast {} {
dict get $data $last
}
}
% mydict add a 1 b 2 c 3
c
% time {mydict getLast} 100000
0.82731 microseconds per iteration
Documentation:
create (method of oo::class),
dict,
lappend,
lindex,
method (object configuration subcommand),
proc,
oo::objdefine (object definition command),
oo::object (class of objects),
set,
time,
variable (object slot subcommand),
{*} (syntax)
I'm seeing [lindex $data end-1] to be faster.
tclsh last.tcl
time_list : 1.0693949999999999 microseconds per iteration
time_dict : 279.470543 microseconds per iteration
last.tcl
set data [dict create]
for {set i 0} {$i < 10000} {incr i} {
dict set data "key_$i" $i
}
set time_dict [time {
set last_key [lindex [dict keys $data] end]
} 1000]
set time_list [time {
set last_key [lindex $data end-1]
} 1000]
puts "time_list : $time_list"
puts "time_dict : $time_dict"
I want have a proc which does something if its' argument is a Tcl 8.5 and above dictionary or not.
I could not find anything straightforward from Tcl dict command.
The code which I could get working is:
proc dict? {dicty} {
expr { [catch { dict info $dicty } ] ? 0 : 1 }
}
Is there anything w/o using catch, something built in?Thanks.
You can test if a value is a dictionary by seeing if it is a list and if it has an even number of elements; all even length lists may be used as dictionaries (though many are naturally not canonical dictionaries because of things like duplicate keys).
proc is-dict {value} {
return [expr {[string is list $value] && ([llength $value]&1) == 0}]
}
You can peek at the actual type in Tcl 8.6 with tcl::unsupported::representation but that's not advised because things like literals are converted to dictionaries on the fly. The following is legal, shows what you can do, and shows the limitations (
% set value {b c d e}
b c d e
% tcl::unsupported::representation $value
value is a pure string with a refcount of 4, object pointer at 0x1010072e0, string representation "b c d e"
% dict size $value
2
% tcl::unsupported::representation $value
value is a dict with a refcount of 4, object pointer at 0x1010072e0, internal representation 0x10180fd10:0x0, string representation "b c d e"
% dict set value f g;tcl::unsupported::representation $value
value is a dict with a refcount of 2, object pointer at 0x1008f00c0, internal representation 0x10101eb10:0x0, no string representation
% string length $value
11
% tcl::unsupported::representation $value
value is a string with a refcount of 2, object pointer at 0x1008f00c0, internal representation 0x100901890:0x0, string representation "b c d e f g"
% dict size $value;tcl::unsupported::representation $value
value is a dict with a refcount of 2, object pointer at 0x1008f00c0, internal representation 0x1008c7510:0x0, string representation "b c d e f g"
As you can see, types are a bit slippery in Tcl (by design) so you're strongly advised to not rely on them at all.
Your approach is flawed because Tcl has dynamic type system where the actual type of a value is able to morph dynamically and depends on the commands applied to it—observe:
$ tclsh
% info pa
8.5.11
% dict info {a b}
1 entries in table, 4 buckets
number of buckets with 0 entries: 3
number of buckets with 1 entries: 1
number of buckets with 2 entries: 0
number of buckets with 3 entries: 0
number of buckets with 4 entries: 0
number of buckets with 5 entries: 0
number of buckets with 6 entries: 0
number of buckets with 7 entries: 0
number of buckets with 8 entries: 0
number of buckets with 9 entries: 0
number of buckets with 10 or more entries: 0
average search distance for entry: 1.0
% llength {a b}
2
% string len {a b}
3
%
As you can see, the same value {a b} is a dictionary, a list and a string: in each case, the value acquires its "real" type in the very moment a Tcl command expecting a value of certain type converts the "default" type of the value, which is string, to the one the command operates on.
You should understand by now that trying to make a call dict? {a b} has little sence as the value {a b} is a perfect dict as well as a perfect list as well as a perfect string, and it could be, say, a perfect tuple if there are custom commands in the current interpreter working on tuples (lists of fixed length).
Hence the real approach you should take is to just blindly use dict command on those values passed to your commands you expect to contain dictionaries. If a user will manage to pass to your command something which is not interpretable as a dictionary, the dict command will fail, and that's a good thing to do as such an error is not really recoverable (it's a programming error).
Any attempt to count on a value's specific type is going again the grain of the very idea of the Tcl's implicit/dynamic typing. It's even true for the Tcl C API.
If you really meant to ask how to be sure the current Tcl version supports dict command, and not about the type of a particular value, test the Tcl's version somewhere at startup and save this as a flag, like this:
set hasDicts [expr {[package vcompare [info tclversion] 8.5] >= 0}]
But note that your code relying on the hasDicts value is now in some gray zone because if the user is not supplying you values you process with the dict command then what command you use to process them?
Please also note that the dict command can be added to a Tcl 8.4 interpreter in the form of the loadable module (see this).
set windowSize 0
for {set i 0} {$i < 14} {incr i} {
set $windowSize [expr $windowSize + [$tcp($i) set cwnd_]]
}
puts "$windowSize"
This prints out zero, when the values being added are non zero. How to do this without a temp var? Holla if you love TCL. ...dead silence.
set $windowSize substitutes the value of $windowSize before running the command.
You want set windowSize [expr ...], or even simpler:
incr windowSize [$tcp($i) set cwnd_]