Richard Suchenwirth 2002-05-15 - The following code gets maps of predicted precipitation (for North Atlantic, Europe, and parts of adjacent continents) for the next 15 days, in 12 hour steps, from a German weather station via HTTP and displays them in a canvas.
proc cycle listName { upvar 1 $listName list set res [lindex $list 0] set list [concat [lrange $list 1 end] [list $res]] } proc every {ms body} {eval $body; after $ms [info level 0]} package require http # http::config -proxyhost proxy -proxyport 80 set prefix http://129.13.102.67/pics/Rvtmrf set suffix 4.gif pack [canvas .c -width 800 -height 680] -expand 1 -fill both wm title . "Loading..." for {set i 12} {$i<=504} {incr i 12} { set gif [http::data [http::geturl $prefix$i$suffix]] if ![catch {lappend ims [image create photo im$i -data $gif]}] { .c create image 0 0 -anchor nw -image im$i -tag im$i } } wm title . "Film" bind . q exit bind . <Control-c> exit every 1000 {.c raise [lindex [cycle ::ims] 0]}
KBK I found that the above caused my Windows desktop to, uhhhm, "become unresponsive." Apparently, the Windows implementation, at least on my machine, can't cope with 32 images of that size inside a canvas at once.
Changing so that the canvas has only two image objects and loading them in alternation helps a lot. (It also allows the animation to start while the images are still downloading, if done right.) Here's an alternative implementation:
proc every {ms body} {eval $body; after $ms [info level 0]} proc cycleImages { } { variable ims variable imsIndex variable buffer if { [llength $ims] > 0 } { .c raise buffer$buffer wm title . "image $imsIndex" set buffer [expr { 2 - $buffer }] incr imsIndex if { $imsIndex >= [llength $ims] } { set imsIndex 0 } .c itemconfig buffer$buffer -image [lindex $ims $imsIndex] } } proc loadImage { i } { variable prefix variable suffix if { $i > 504 } return http::geturl $prefix$i$suffix -command [list loadFinished $i] } proc loadFinished { i token } { variable ims lappend ims [image create photo -data [http::data $token]] http::cleanup $token after 0 [list loadImage [expr { $i + 12 }]] } package require http # http::config -proxyhost webcache -proxyport 8080 set prefix http://129.13.102.67/pics/Rvtmrf set suffix 4.gif pack [canvas .c -width 800 -height 680 -bg white] -expand 1 -fill both .c create image 10 10 -anchor nw -tag buffer1 .c create image 10 10 -anchor nw -tag buffer2 set ims {} set imsIndex 0 set buffer 1 bind . q exit bind . <Control-c> exit every 1000 cycleImages loadImage 12
Donal Fellows - Now, I'm lucky enough to have a machine big enough to take all the images, but I don't like the way that they load; I'd like to issue a bunch of HTTP requests at once and get things back ASAP (I'm on quite a big network pipe here) so I do something like this (min. Tcl version 8.4):
package require http # http::config -proxyhost proxy -proxyport 80 proc every {ms body} {eval $body; after $ms [info level 0]} set prefix http://129.13.102.67/pics/Rvtmrf set suffix 4.gif set ims {} pack [canvas .c -width 800 -height 680] -expand 1 -fill both wm title . "Loading..." update set throttle 6 set cmds {} proc loadImage {i step limit} { global prefix suffix if { $i > $limit } return loadImageCore $prefix$i$suffix after 150 loadImage [expr {$i + $step}] $step $limit } proc loadImageCore {url} { global ims cmds throttle set l [llength $ims] lappend ims {} if {$throttle < 1} { lappend cmds [list \ http::geturl $url -command [list loadFinished $l]] } else { incr throttle -1 http::geturl $url -command [list loadFinished $l] } } proc loadFinished { l token } { global ims throttle incr throttle set image [image create photo -data [http::data $token]] lset ims $l [.c create image 0 0 -anchor nw -image $image] http::cleanup $token after 1000 anotherCommand } proc anotherCommand {} { global cmds if {[llength $cmds]} { set cmd [lindex $cmds 0] set cmds [lrange $cmds 1 end] uplevel #0 $cmd } } set idx 0 proc cycleImage {} { global ims idx set item [lindex $ims $idx] if {$item ne ""} { .c raise $item } if {[incr idx] >= [llength $ims]} { set idx 0 } } every [expr {1000/15}] {cycleImage} loadImage 12 12 504 wm title . "Film" bind . q exit bind . <Control-c> exit
Alas, asynchronous HTTP has quite a hefty synchronous start-up phase on this system. :^(
Multiply your possibilities by changing the trailing digit in the URL ("4.gif" above):
'Nother massive source of weather data is METAR [L1 ]. Not predictive but reporting current conditions (hourly, I think). Using a well-defined textual dataset with lines such as:
KCPC 190751Z AUTO 00000KT 10SM SCT015 OVC110 21/19 A3016 RMK AO2 705
That's an airport code, timecode, and then al sorts of weather info. There are several sources of collected data, e.g. [L2 ].
MPJ: Jason Tang has a nice Weather Ticker that uses METAR data for updates (with a very nice interface for country regions). Now if I can just get him to post the package!!! (see his stock ticker, TclTicker for a similar type of interface)
Hmm.... are there any contour plot solutions for Tcl? -jcw
RS: Iain Findleton reported that he is using the turtle graphics code from Turtleshell, which was intended more as demo for kids, to plot weather maps which he receives in relative coordinates...
AM Believe it or not: Vince Darley maintains "Pltk" at [L3 ], a package that does that sort of plots. (Now at [L4 ] -jcw)
As for parsing METAR data files - turns out that it has already been done, see Jason Tang's TclWeather. Good. -jcw
The 4-letter "ICAO identifiers" define each airport, there's a list with some 6000 entries along with names and longitude/latitude at [L5 ] (about 500 Kb ascii, field description at [L6 ]).
One could take TclWorld, fetch current temperatures on there, and then draw a contour plot... hmm, that could be fun -jcw