Snippets

John Peck Learning about plotting time-based data from a continuously-updating file

Created by John Peck
#!/opt/ActiveTcl-8.6/bin/tclsh
# Hey Emacs, use -*- Tcl -*- mode

set scriptname plottest
set output_directory output

# ----------------------- Gnuplot settings ----------------------------

# The wxt terminal can keep windows alive after the gnuplot process
# exits.  This allows calling multiple persistent windows which allow
# zooming and annotation.
set gnuplot_terminal wxt

set gnuplot "c:/Program Files/gnuplot/bin/wgnuplot.exe"

proc read_file {filename} {
    # Return a list of lines from an input file.  Strips out header.
    #
    # Arguments:
    #   filename -- relative or full path to file
    if { [catch {open $filename r} fid] } {
	    puts "Could not open file $filename"
	return
    }
    try {
	set fid [open $filename r]
    } trap {} {message optdict} {
	puts $message
	exit
    }
    set raw_datafile_list [split [read $fid] "\n"]
    foreach line $raw_datafile_list {
	if {[string first "%" $line] == 0} {
	    # The line starts with %, so this is a header line
	    continue
	} else {
	    lappend datafile_list $line
	}
    }
    return $datafile_list
}

proc write_gnuplot_script {measurement_dict data_file_list} {
    # Write a gnuplot script to plot data in datafile
    #
    # Arguments:
    #   measurement_dict -- Dictionary of measurements made on the data
    #   data_file_list -- List of files to be plotted
    global gnuplot_terminal
    global scriptname
    global params
    global output_directory
    set output_file_name "$output_directory/gnuplot.gp"
    try {
	set fid [open $output_file_name w]
    } trap {} {message optdict} {
	puts $message
    }
    # Annotation x postion in graph (0 --> 1) coordinates
    set anno_x 0.05
    # Annotation y position in graph (0 --> 1) coordinates
    set anno_y 0.4
    # Spacing between annotation lines in graph (0 --> 1) coordinates
    set anno_incr 0.05
    puts $fid "reset"
    puts $fid "set terminal $gnuplot_terminal size 800,600"
    puts $fid "set datafile separator ','"
    puts $fid "set format y '%0.0s %c'"
    puts $fid "set xdata time"
    puts $fid "set key above left"
    puts $fid "timeformat = '%Y-%m-%d %H:%M:%S'"
    # Use right justification for xtics to keep them from disappearing
    puts $fid "set xtics rotate by 90 offset graph 0,0 right"
    puts $fid "set format x '%H:%M:%.3S'"
    # puts $fid "set xlabel 'Time'"
    puts $fid "set ylabel 'Data'"
    # Add annotations
    foreach measurement [dict keys $measurement_dict] {
	set annotation "[dict get $measurement_dict $measurement title] = "
	# Number formatted to use an engineering SI prefix
	set value [dict get $measurement_dict $measurement value]
	if [string is double $value] {
	    # This is a floating-point number
	    set enhanced true
	    set eng_number [lindex [eng $value] 0]
	    set eng_prefix [lindex [eng $value] 1]
	    set value [format "%0.1f" $eng_number]
	    append annotation "$value $eng_prefix"d
	    append annotation "[dict get $measurement_dict $measurement units]"		    
	} else {
	    # This is just a string.  Turn off enhanced mode to avoid
	    # underscores becoming subscripts
	    append annotation $value
	    set enhanced false
	}
	if $enhanced {
	    puts $fid "set label '$annotation' at graph $anno_x,$anno_y"	    
	} else {
	    puts $fid "set label '$annotation' at graph $anno_x,$anno_y noenhanced"
	}
	set anno_y [expr $anno_y - $anno_incr]
    }
    set linetype 0
    set output_string "plot "
    foreach file_name $data_file_list {
	incr linetype
	while {[lsearch {3 4 5} $linetype] != -1} {
	    # Avoid these linetypes
	    incr linetype
	}
	# puts $fid "yminval = 'A_min'"
	# puts $fid "ymaxval = 'A_max'"
	# puts $fid "set yrange \[yminval:ymaxval\]"
	set title [file tail $file_name]
	append output_string "'$file_name' using (timecolumn(1,timeformat)):2 \
	 with lines linetype \
	 $linetype title '$title' noenhanced,"
    }
    puts $fid [string trim $output_string ", "]
    puts $fid "pause 0"
    puts $fid "reread"
    close $fid
    return $output_file_name
}

########################## Main entry point ##########################

file mkdir $output_directory
set gnuplot_data_filename "makedata_archive.csv"

set measurement_dict [dict create]
set gnuplot_script [write_gnuplot_script $measurement_dict $gnuplot_data_filename]
exec $gnuplot -persist $gnuplot_script

Comments (0)

HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.