Version 6 of A little rain forecaster

Updated 2002-06-19 08:54:14

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

  • 1: Temperature and ground pressure
  • 2: 850 hPa Geopot. (gpdm) and Temperature (C)
  • 3: Ground pressure, clouds in %, ReTop 500/1000 (gpdam)
  • 4: 12 h precipitation in mm until date
  • 5: 2 m temperature (C)
  • 6: 700 hPa Geopot. (gpdm) and vertical movement (hPa/h)
  • 7: Ground pressure (hPa) and 850hPa eq.pot.termperature (C)
  • 8: 2 m dewing point

'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 ].

Hmm.... are there any countour plot solutions for Tcl? -jcw


Arts and crafts of Tcl-Tk programming