An interactive tutorial for Plotchart

Arjen Markus (30 may 2008) Below are the very first steps towards a tutorial for Plotchart.

My first idea was to write it as a man page with pictures in it, but currently the doctools do not yet support pictures in a convenient way. Then I thought it might be nice to have some interactive features ...

And then the idea was born to create a small library that would either convert the text of the tutorial to man page format or convert it into a GUI - after all, we have the text widget to take care of almost all details of displaying text and embedded windows.

So, below is that particular library, incomplete, poor in features but getting 80% of the job done already.

Note:

Right now this is limited to running Tcl code samples, but nothing prevents me or anybody else to expand this to running other applications for which you must edit some input for instance.

# tutorial_code.tcl --
#     Procedures to create an interactive tutorial or a man page
#     in doctools format
#

# manpageOnly --
#     Text to be written to the man page file only
#
# Arguments:
#     text        Text to be written
#
# Result:
#     None
#
# Side effects:
#     The text is copied verbatim
#
proc manpageOnly {text} {
    global outfile
    global mode

    if { $mode == "manpage" } {
        puts $outfile $text
    }
}

# plain --
#     Text to be written in plain form to the text widget or to the file
#
# Arguments:
#     text        Text to be written
#
# Result:
#     None
#
# Side effects:
#     The text is copied verbatim or displayed in the text widget
#
proc plain {text} {
    global outfile
    global mode

    if { $mode == "manpage" } {
        puts $outfile $text
    } else {
        .textw.t insert end [string map {\n\n \n\n \n " "} $text] plain
    }
}

# title --
#     Text to be written as a title
#
# Arguments:
#     text        Text to be written
#
# Result:
#     None
#
# Side effects:
#     The text is copied to the file or the text widget
#
proc title {text} {
    global outfile
    global mode

    if { $mode == "manpage" } {
        puts $outfile "\[section \{$text\}\]"
    } else {
        .textw.t insert end $text title
    }
}

# fixed --
#     Text to be written in non-proportional font
#
# Arguments:
#     text        Text to be written
#
# Result:
#     None
#
# Side effects:
#     The text is copied as an example or displayed in Courier
#
proc fixed {text} {
    global outfile
    global mode

    if { $mode == "manpage" } {
        puts $outfile "\[example \{$text\n\}\]"
    } else {
        .textw.t insert end $text fixed
    }
}

# bullets --
#     Text to be written in the form of a bullet list
#
# Arguments:
#     text        Text to be written
#
# Result:
#     None
#
# Side effects:
#     The text is copied to the output file or displayed in the text
#     widget with the correct formatting for a bullet list
#
proc bullets {text} {
    global outfile
    global mode

    if { $mode == "manpage" } {
        puts $outfile $text
    } else {
        .textw.t insert end $text bullets
    }
}

# hiddenCode --
#     Code to be run once, not visible in the text widget or otherwise
#
# Arguments:
#     code        Code to be run immediately
#
# Result:
#     None
#
# Side effects:
#     The code is run in the global namespace
#
proc hiddenCode {code} {

    uplevel #0 $code

}

# runnableCode --
#     Code to be written to the output file as an example or shown in a
#     embedded text widget. Can be edited and run by pressing the
#     associated push button
#
# Arguments:
#     code        Code to be written or run
#
# Result:
#     None
#
# Side effects:
#     The code is copied to the output file or displayed in an
#     embedded text widget. A push button is added to run the code
#
proc runnableCode {code} {
    global outfile
    global count
    global mode

    if { $mode == "manpage" } {
        puts $outfile "\example \{$text\n\}\]"
    } else {
        incr count
        set frame [frame  .textw.t.frame$count]
        set tcode [text   $frame.t -background lightblue \
                       -wrap none \
                       -xscrollcommand [list $frame.xscroll set] \
                       -yscrollcommand [list $frame.yscroll set]]
        set brun  [button .textw.b$count -text "Run" -command $code -font "Helvetica, 12"]

        set xbar [scrollbar $frame.xscroll -orient horizontal -command [list $tcode xview]]
        set ybar [scrollbar $frame.yscroll -orient vertical   -command [list $tcode yview]]
        grid $tcode  $ybar -sticky news
        grid $xbar   -     -sticky news
        grid columnconfigure $frame 0 -weight 1
        grid columnconfigure $frame 1 -weight 0
        grid rowconfigure    $frame 0 -weight 1
        grid rowconfigure    $frame 1 -weight 0

        .textw.t window create end -window $frame
        .textw.t insert end \n
        .textw.t window create end -window $brun

        $tcode tag configure code -font "Courier 12"
        $tcode insert end $code code
    }
}

# preparation --
#     Create the text widget, open the file and set a few global parameters
#
set count 0
set mode  ""
if { $mode == "manpage" } {

    # TODO

} else {
    toplevel  .textw
    text      .textw.t -yscrollcommand {.textw.yscroll set} -wrap word
    scrollbar .textw.yscroll -orient vertical -command {.textw.t yview}
    grid      .textw.t .textw.yscroll -sticky news
    grid columnconfigure .textw 0 -weight 1
    grid columnconfigure .textw 1 -weight 0
    grid rowconfigure    .textw 0 -weight 1

    .textw.t tag configure plain -font "Times 12"
    .textw.t tag configure fixed -font "Courier 12"
    .textw.t tag configure bullets -font "Times 12"
    .textw.t tag configure title -font "Helvetica 14 bold"


    # TODO: wm protocol WM_DELETE ...
} 

And of course, the humble beginnings of the tutorial, illustrating the use of this library:

# pl_tutorial.tcl --
#     Interactive tutorial for Plotchart
#
source "tutorial_code.tcl"

manpageOnly {
[comment {-*- tcl -*- doctools manpage}]
[manpage_begin Plotchart n 1.5]
[copyright {2008 Arjen Markus <[email protected]>}]
[moddesc   Plotchart]
[titledesc {Tutorial to the Plotchart package}]
}

title {
Tutorial for the Plotchart package
}

plain {
Plotchart is Tcl-only package to create xy-plots, barcharts, piecharts
and many other types of graphical presentations. This tutorial is
intended to help you get started using it. It does not describe every
feature of Plotchart, you should consult the manual for that.

Rather, this tutorial will show:
}

bullets {
* How to use Plotchart to create several of the plots and charts
mentioned above
* How to customise various aspects
* Some of the gory details
}

plain {
Throughout this tutorial we will use a fixed set of data:
}

fixed {
chart       2008-05-18      17:25   1440    1081    27      94
axis        2008-05-18      17:26   940     712     20      86
pack        2008-02-24      08:22   378     258     7       37
priv        2008-05-18      17:18   1837    1238    40      167
annot       2008-02-22      13:03   376     275     7       22
config      2008-02-22      11:25   162     123     2       12
scaling     2008-02-22      10:23   148     109     4       15
plot3d      2007-09-07      11:47   300     203     5       34
contour     2005-04-15      13:42   1697    1131    19      151
gantt       2005-06-15      11:12   333     209     7       25
business    2007-09-07      12:15   382     246     7       30
}
hiddenCode {
set data {
{chart       2008-05-18      17:25   1440    1081    27      94}
{axis        2008-05-18      17:26   940     712     20      86}
{pack        2008-02-24      08:22   378     258     7       37}
{priv        2008-05-18      17:18   1837    1238    40      167}
{annot       2008-02-22      13:03   376     275     7       22}
{config      2008-02-22      11:25   162     123     2       12}
{scaling     2008-02-22      10:23   148     109     4       15}
{plot3d      2007-09-07      11:47   300     203     5       34}
{contour     2005-04-15      13:42   1697    1131    19      151}
{gantt       2005-06-15      11:12   333     209     7       25}
{business    2007-09-07      12:15   382     246     7       30}
}
}

plain {
These are simple software metrics from the Plotchart source files:
}

bullets {
* The abbreviated name of the file, date and time of the last modification
* Total number of lines and number of lines without comments
* Number of procedures
* Number of if and switch statements, for, foreach and while loops
}

plain {
Rather than use fictitious data, it seemed nice to use these data,
related in some way to Plotchart itself.

Now, let us plot the number of lines versus the number of procedures:
}

runnableCode {
    package require Plotchart

    #
    # Create the canvas that will hold the plot
    #
    canvas .c -width 400 -height 300 -background white
    pack .c -fill both

    #
    # Create the plot
    #
    set p [::Plotchart::createXYPlot .c {0 40 10} {0 1500 250}]

    #
    #
    # Get the data (via the convenience procedure "column") and plot the
    # data points
    #
    # ...
}