Updated 2013-03-05 02:01:25 by pooryorick

Summary  edit

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.

DKF 2003-06-27: This code no longer works because the site no longer provides the data (or at least not in the same way...?)

RS: fixed, runs again :)

Description  edit

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/Rtavn ;# fixed
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

DKF: 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
  • 1: 850 hPa Geopot. (gpdm) and Temperature (C)
  • 1: Ground pressure, clouds in %, ReTop 500/1000 (gpdam)
  • 1: 12 h precipitation in mm until date
  • 1: 2 m temperature (C)
  • 1: 700 hPa Geopot. (gpdm) and vertical movement (hPa/h)
  • 1: Ground pressure (hPa) and 850hPa eq.pot.termperature (C)
  • 1: 2 m dewing point

'Nother massive source of weather data is METAR [1]. 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. [2].

[jcs]: Hmm.... are there any contour plot solutions for Tcl?

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 Plplot ("Plplotter" widget) at [3], a package that does that sort of plots.

jcw: (Now at [4], Vince adds that the 'plplot' sourceforge project has the Plplotter code partially integrated into the main branch of plplot, but the TEA configure/build stuff is in a 'tea' branch off the main project branch. Unfortunately TEA was such a disaster that everyone's patience was exhausted before the code could get incorporated into the main tree. It is a very nice plotting widget, however! (I've used it both for my thesis work and in a commercial product). A binary release of plplot for Windows is available.

jcw: As for parsing METAR data files - turns out that it has already been done, see Jason Tang's TclWeather. Good.

MPJ: I have been using TclWeather for a couple of months now (even works behind a proxy). You may also want to see his stock ticker, TclStock, application.

The 4-letter "ICAO identifiers" define each airport, there's a list with some 6000 entries along with names and longitude/latitude at [5] (about 500 Kb ascii, field description at [6]).

jcw: One could take TclWorld, fetch current temperatures on there, and then draw a contour plot... hmm, that could be fun

Jason Tang: Indeed, I have written an applet that downloads and parses the METAR data for nearly any place on the planet. I haven't finished cleaning up and documenting TclWeather yet; it'll be ready Real Soon Now(tm). It uses my lexical scanner, (insert plug here) fickle to break down a METAR report into its individual parts. Update: Go to TclWeather.

See Also  edit

Tcl and the weather