Version 19 of A little rain forecaster

Updated 2002-06-23 00:36:15

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

MPJ: Jason Tang Has a nice Weather Ticker that uses METAR data for updates (very nice interface). 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


Arts and crafts of Tcl-Tk programming