Initial commit.

This commit is contained in:
2016-02-18 14:53:30 +01:00
commit 8e93ca7a95
2215 changed files with 341269 additions and 0 deletions

View File

@@ -0,0 +1,72 @@
spread We have designed and constructed an interactive spreadsheet
interface to S/Splus that maintains the complete power and
generality of the S language. At user level, the interface
behaves like the popular spreadsheet programs available for
personal computers: one or more S data objects (matrices or
three-way arrays) are displayed on the screen. The user
graphically (with mouse or cursor motion) identifies a cell
for review, and possible updating, of its contents. Macros
containing arbitrary S expressions can be associated with
the entire spread.frame or one of its cells. The
spreadsheet is designed in a modular fashion with
device-specific methods for the display and updating of
spreadsheet objects. We include methods for two devices:
the generic S graphics device and a character based device
using the emacs 19 environment.
Richard M. Heiberger (rmh@astro.ocis.temple.edu)
Magnus Mengelbier (magnus@astro.ocis.temple.edu)
The interface is described in
\item Heiberger, Richard M., and Magnus Mengelbier (1995, to appear)
``Design of a Spreadsheet Interface for S,''
{\it Proceedings of the American Statistical Association},
Section on Statistical Graphics.
This is placeholder announcement. The files will be
available on statlib after one more level of testing.
Files in this distribution:
README Abstract, file listing, and setup instructions.
sprd3d.how Instructions for spread.frame users.
sprd-emc.s S for emacs driver
sprd-grd.s S for class="grade"
sprd-spr.s S for class="spread" This is the primary set of functions.
sprd-txt.s S for graphics device driver based on text() command.
sprd-int.el emacs lisp file
Load this file into emacs 19 each time you start a
spread.frame session.
gradexmp.s S example
Setup Instructions
The emacs spreadsheet interface for S consists of four S files
"sprd-*.s" and one emacs lisp file "sprd-int.el".
1. Create a new directory to store the four S files "sprd-*.s" and one
emacs lisp file "sprd-int.el". I use "/disk5/rmh/sprd3d/". You might
wish to place it under the directory where you store other S/Splus
libraries.
2. Make a new .Data, "/disk5/rmh/sprd3d/.Data", start S/Splus, and
source the four sprd-*.s files:
> source("sprd-emc.s")
> source("sprd-grd.s")
> source("sprd-spr.s")
> source("sprd-txt.s")
> q()
3. The directory /disk5/rmh/sprd3d/ should now be treated as a
library directory and should not be further touched. All further work
using the spread.frames should be done in a different directory.
4. See the file sprd3d.how for user instructions. You may look at
the file "gradexmp.s" for an example.

View File

@@ -0,0 +1,337 @@
;; spreadsheet in S, S-mode or stand-alone
;; Richard M. Heiberger
;; 1996
;; S-mode
;; Load this file from a running *S* window after starting S/Splus with M-x S
;; or
;; stand-alone
;; Load this file from the dired window in which .Data exists.
;(set-variable 'buffers-menu-max-size nil)
(defvar spread-directory (concat "/tmp/" (make-temp-name "spr"))
"Directory in which to store ascii spreadsheet displays.")
(defvar spread-command-file (concat spread-directory "/*command*")
"File through which S will communicate with emacs.")
(defvar spread-directory-p nil
"predicate value non-nil when directory has been defined.")
(defun print-find-emacs nil "display spread.frame from minibuffer" (interactive)
(spread-print-find (read-string "spread.frame: ") t))
(defun emacs-rc nil "" (interactive)
(emacs-cell "1")
)
(defun emacs-macro nil "" (interactive)
(emacs-cell "2")
)
(defun emacs-macro-control-text nil "" (interactive)
(emacs-cell "4")
)
(defun emacs-macro-print-text nil "" (interactive)
(emacs-cell "5")
)
(defun emacs-cell (result-type) "" (interactive)
(setq spread-name (buffer-name))
(setq r (count-lines 1 (point)))
(setq c (current-column))
(set-buffer S-buffer)
(spread-insert
(format "emacs.cell('%s', %s, %s, %s)"
spread-name r c result-type
)
)
(save-excursion
(set-buffer "*command*")
(revert-t-t)
(goto-char (point-min))
(setq beg (point)) (end-of-line)
(if (equal result-type "4")
(progn
(setq command (buffer-substring beg (point)))
(set-buffer S-buffer)
(spread-insert command)
)
(setq command (read-string "> " (buffer-substring beg (point))))
(set-buffer S-buffer)
(spread-insert command)
(spread-insert "invisible(assign(.Active, x))")
(spread-print-find spread-name nil)
(goto-line r)(forward-char c)
))
)
(defun spread-insert (spread-command) "" (interactive)
(goto-char (point-max))
(insert spread-command)
(comint-send-input)
(accept-process-output spread-process)
)
(defun revert-t-t nil "revert-buffer with no questions asked"
(interactive)
(revert-buffer t t)
)
(defun revert-t-t-read-only nil "revert-buffer, no questions, read-only"
(interactive)
(revert-buffer t t)
(setq buffer-read-only t)
)
(defvar spread-mode-map nil "Keymap for Spread mode.")
(if spread-mode-map
nil
(setq spread-mode-map (make-sparse-keymap))
(define-key spread-mode-map "\C-cv" 'revert-t-t-read-only)
(define-key spread-mode-map "\C-m" 'emacs-rc)
(define-key spread-mode-map "\C-cc" 'emacs-macro)
(define-key spread-mode-map "\C-cs" 'emacs-macro-control-text)
(define-key spread-mode-map "\C-cp" 'emacs-macro-print-text)
(define-key spread-mode-map "f" 'emacs-print-find-emacs)
(define-key spread-mode-map [mouse-2] 'spread-mouse-print-find-emacs)
(define-key spread-mode-map [mouse-3] 'spread-mouse-rc)
)
(defun spread-mouse-rc (event) "move point then enter"
(interactive "e")
(mouse-set-point event)
(emacs-rc)
)
(defun spread-mouse-print-find-emacs (event) "move point then find file"
(interactive "e")
(mouse-set-point event)
(emacs-print-find-emacs)
)
(defun spread-mode () "Major mode for spreadsheets.\\{spread-mode-map}"
(interactive)
(kill-all-local-variables)
(make-local-variable 'beg)
(make-local-variable 'command)
(use-local-map spread-mode-map)
(setq mode-name "Spread")
(setq major-mode 'spread-mode)
(if (equal (buffer-name) ".Registry") (spread-highlight-macro))
(setq buffer-read-only t)
)
;; from dired.el L547
; (put-text-property (point)
; (save-excursion
; (dired-move-to-end-of-filename)
; (point))
; 'mouse-face 'highlight)
;
;; (put-text-property (point) (mark) 'mouse-face 'highlight)
(defun spread-highlight-macro nil
"highlight spread.frame names for mouse access"
(interactive)
(save-excursion
(goto-char (point-min))
(search-forward "**macro**")(forward-char)
(toggle-read-only -1)
(while (progn
(setq beg (point))(end-of-line)
(not (= beg (point)))
)
(put-text-property beg (1-(point)) 'mouse-face 'highlight)
(forward-char)
)
(toggle-read-only 1)
)
(save-buffer)
)
(defun emacs-print-find-emacs nil "" (interactive)
(beginning-of-line)
(setq beg (point)) (end-of-line) (backward-char)
(setq spread-name (buffer-substring beg (point)))
(spread-print-find spread-name nil)
)
(defun find-spread-frame-directory nil
"Locate directory in which spread.frame functions are stored."
(list-command-history)
(set-buffer "*Command History*")
(goto-char (point-min))
(search-forward "(load-file ")
(goto-char (1+ (match-end 0)))(setq beg (point))
(end-of-line)(search-backward "/")
(goto-char (match-end 0))
(setq spread-frame-directory
(expand-file-name (buffer-substring beg (point))))
(kill-buffer "*Command History*")
)
(defvar inferior-spread-mode nil
"Non-nil if using inferior-spread-mode as a minor mode of some other mode.")
(make-variable-buffer-local 'inferior-spread-mode)
(put 'inferior-spread-mode 'permanent-local t)
(or (assq 'inferior-spread-mode minor-mode-alist)
(setq minor-mode-alist (append minor-mode-alist
(list '(inferior-spread-mode " spread")))))
(defvar inferior-spread-mode-map nil)
(if inferior-spread-mode-map
nil
(setq inferior-spread-mode-map (make-sparse-keymap))
(define-key inferior-spread-mode-map "\C-cv" 'revert-t-t)
(define-key inferior-spread-mode-map "\C-cr" 'print-find-emacs))
(or (assq 'inferior-spread-mode minor-mode-map-alist)
(setq minor-mode-map-alist
(cons (cons 'inferior-spread-mode inferior-spread-mode-map)
minor-mode-map-alist)))
(defun inferior-spread-mode (&optional arg)
"Toggle Inferior Spread mode.
With arg, turn Inferior Spread mode on if arg is positive, off otherwise."
(interactive "P")
(setq inferior-spread-mode
(if (null arg) (not inferior-spread-mode)
(> (prefix-numeric-value arg) 0)))
(if inferior-spread-mode
(progn
(set-process-filter spread-process 'comint-output-filter)
(set-variable 'comint-output-filter-functions
'(spread-output-filter
comint-postoutput-scroll-to-bottom))
(set-variable 'comint-scroll-to-bottom-on-output "this")
(set-variable 'comint-scroll-show-maximum-output t)
(force-mode-line-update))
(message "Don't know how to turn off Inferior Spread mode")))
(defun spread-process ()
"Start stand-alone S process to run spread."
(comint-run S-program)
(setq spread-process (get-buffer-process (current-buffer)))
(setq comint-prompt-regexp shell-prompt-pattern)
(if (not(file-writable-p ".Data/.Audit"))
(accept-process-output spread-process))
(accept-process-output spread-process)
spread-process
)
(defun spread-output-filter (str)
"detect errors in S output"
(if (or
(string-match "Dumped" str)
(string-match "Error" str)
)
(progn
(switch-to-buffer-other-window S-buffer)
(comint-show-maximum-output)
(set-variable 'quit-flag t); beeps and writes "quit" in the message area
)
)
)
(defun spread-print-find (spread-name update-Registry)
"Place SPREAD-NAME in foreground of S-buffer (*S* or *Splus*),
update .Registry and revert buffer when UPDATE-REGISTRY is t,
print all views of spread.frame associated with SPREAD-NAME in .Registry
to /tmp/spr***** directory, and find or revert all views into emacs buffers."
(interactive)
(set-buffer S-buffer)
(spread-insert
(format "print.find.emacs('%s', update.Registry=%s)"
spread-name (if update-Registry "T" "F")))
(if update-Registry
(save-excursion (spread-find-file ".Registry")))
(spread-print-sprds)
(switch-to-buffer spread-name)
)
(defun spread-print-sprds () "Display in buffers all views of spread.frame"
(interactive)
(save-excursion
(set-buffer "*command*")
(revert-t-t)
(goto-char (point-min))
(while (< (point) (point-max))
(set-buffer "*command*")
(setq beg (point)) (end-of-line)
(setq spread-name-i (buffer-substring beg (point)))
(save-excursion (spread-find-file spread-name-i))
(forward-line)))
)
(defun spread-find-file (spread-name) "Display one view of spread.frame"
(interactive)
(switch-to-buffer spread-name)
(if (buffer-file-name)
(revert-t-t-read-only)
(kill-buffer spread-name)
(find-file (concat spread-directory "/" spread-name))
)
(spread-mode)
)
(defun spread-start () "load emacs spread.frame handler"
(if (equal major-mode 'inferior-S-mode)
(progn
(setq spread-mode "S-mode")
(setq S-buffer (current-buffer)))
(if (equal major-mode 'dired-mode)
(progn
(setq spread-mode "stand-alone")
(setq S-program (read-string "Splus or S? " "Splus"))
(setq S-buffer (concat "*" (file-name-nondirectory S-program) "*"))
(if (not (get-buffer S-buffer))
(get-buffer-create S-buffer))
(if (get-buffer-process S-buffer) (set-variable 'quit-flag t)))
(set-variable 'quit-flag t)))
(setq spread-home-directory default-directory)
(find-spread-frame-directory)
(if (not spread-directory-p)
(progn (make-directory spread-directory)
(setq spread-directory-p t)))
(set-buffer S-buffer)
(cd spread-home-directory)
(setq spread-process
(if (equal spread-mode "stand-alone")
(spread-process)
(get-buffer-process (current-buffer))))
(inferior-spread-mode 1)
(spread-insert
(format "assign('.spread.Data',attach('%s.Data'),frame=0)"
spread-frame-directory))
(spread-insert
(format "emacs.start('%s')" spread-directory))
(find-file spread-command-file)
(spread-find-file ".Registry")
)
;; start it up
(spread-start)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,18 @@
who <- c(
"Aaaaa",
"Bbbbb",
"Cccc",
"Zzzzzzz",
"maximum")
what <- c("1a","1b","1c","1d","1e","1f","1g",
"1h","2a","2b","2c")
x <- matrix(0, length(who), length(what),
dimnames=list(who,what))
x["maximum",] <- c(5,5,6,4,20,6,16,8,10,10,10)
section.7 <- as.grade(x)

View File

@@ -0,0 +1,280 @@
#-*-Fundamental-*-
col.spacing <- function(x)
{
rn.w <- if (length(dimnames(x)[[1]]) > 0) max(nchar(dimnames(x)[[1]]))
else nchar(as.character(nrow(x)))+3
col.w <- apply(x, 2, function(x) nchar(format(x))[1])
dn.w <- if (length(dimnames(x)[[2]]) > 0) nchar(dimnames(x)[[2]])
else nchar(as.character(ncol(x)))+3
col.w <- ifelse( col.w > dn.w , col.w, dn.w)
cumsum(c(rn.w,col.w)+1)
}
emacs.expr <- function(x, i, j=i[2], result.type)
# 1. emacs.rc
# 2. emacs.macro
# 3. emacs.macro.text(deparse.result=T) #default for index.value
# 4. emacs.macro.text(deparse.result=F)
# 1. assign expression to cell or to macro
# 2. evaluate macro expression
# 3. retrieve macro expression
# 4. construct control.text() expression from macro name
# 5. construct print.text() expression from macro name
{
# i and j are integer scalars
if (missing(j)) {j <- i[2] ; i <- i[1]}
if ((.Active == .Active.buffer) && (length(dim(x)) > 2))
stop("Must use rectangular slice, not 3d buffer")
if (i <= nrow(x) && result.type==1)
return(expr.rc(x, c(i, j)))
if (!inherits(x, "spread")) stop("Not a spread.frame")
mm <- (nrow(x)+1):(nrow(x)+2+length(macro(x)))
bb <- mm[length(mm)]+(1:(2+length(before(x))))
aa <- bb[length(bb)]+(1:(2+length(after(x))))
find.expr <- function(type.x, kk, type, result.type)
{
if (kk>0) {
iv <- index.value(names(type.x), kk,
!((result.type == 4) || (result.type == 5)))
switch(result.type,
paste(type, "(x)[", iv, "] <- expression(",
expr.value(type.x[kk],1), ")"),
paste("x <- eval.spread(x, ", type, "(x)[", iv, "] )" ),
deparse(eval(parse(text=paste(type, "(x)[", iv, "]")))[[1]]),
paste(iv, "<- control.text(", iv, ")"),
paste(iv, "<- print.text(", iv, ")")
)
}
else if (result.type==1) paste(type, "(x)[\"\"] <- expression()")
else NULL
}
k <- match(i, mm, 0)
if (k) return(find.expr(macro(x), k-2, "macro", result.type))
k <- match(i, bb, 0)
if (k) return(find.expr(before(x), k-2, "before", result.type))
k <- match(i, aa, 0)
if (k) return(find.expr(after(x), k-2, "after", result.type))
}
cell.rc.emacs <- function(x, e.r, e.c)
{
x.r <- ifelse(e.c == 0, e.r, e.r-1)
x.c <- sum(e.c >= col.spacing(x))
c(row=x.r, col=x.c)
}
print.update.emacs <- function(x, ...,
file=paste(.spread.directory, .Active.buffer, sep="/"))
{
sink(file)
print(x, ...)
xs <- get(.Active)
if (inherits(xs, "spread"))
{
print.spread.macro(xs, macro)
print.spread.macro(xs, before)
print.spread.macro(xs, after)
}
sink()
invisible(x)
}
print.spread.macro <- function(x, macro)
{
cat("\n**", as.character(substitute(macro)), "**\n", sep="")
ne <- names(macro(x))
if (length(ne))
for (i in 1:length(ne))
cat(index.value(ne,i,F),"\n")
}
as.two.way.array <- function(x, subs=parse(text=.Active.buffer)[[1]][-(1:2)])
{
if (length(dim(x))==2) return(x)
# This is designed for 3 way arrays with
# two missing and one specified dimension.
# If the drop parameter exists, it is over-ridden.
subs$drop <- NULL
which.subs <- (sapply(subs,length)==0)
dnx <- dimnames(x)[which.subs]
dimnames(x) <- NULL
dim(x) <- dim(x)[which.subs]
dimnames(x) <- dnx
x
}
fg <- function( sprdname=.Active )
# sprdname = character name, possibly subscripted
{
if (is.na(match(sprdname, names(macro(.Registry))))) {
macro(.Registry)[sprdname] <- sprdname
assign(".Registry", .Registry, where=1 )
}
assign(".Active.buffer", sprdname, frame=0 )
assign(".Active", find.names(sprdname), frame=0 )
assign("x", eval(parse(text=.Active)), where=1 )
assign("x.buffer", where=1,
if (.Active.buffer==.Active) x
else as.two.way.array(eval(parse(text=.Active.buffer))))
invisible(sprdname)
}
control.emacs <- function(x)
{
#this is a fake function
#emacs does the work
# control.emacs never gets called when emacs is in control.
# RET in spread window puts old command in minibuffer:
# emacs sends
# emacs.cell('spreadname', e.r, e.c, result.type)
# emacs reads the file written by the above and
# asks the user to revise it in the minibuffer.
# RET in minibuffer puts revised command in S buffer,
# and causes the revised command to be executed, updating the spreadsheet.
# emacs issues
# invisible(assign(.Active, x))
# to place the object in x into the object named in .Active
# emacs issues
# print.find.emacs('spreadname', update.Registry=F)
# to update all buffers showing views of the object named in .Active
# When S gets control back, the command has been executed and the
# spreadsheet has been updated
}
#emacs usage
#load-file S-spread.el
#In the *S* buffer, type ^Cr to place a spread.frame or 2-way or 3-way array
# into a spread.frame buffer.
#In the spread.frame buffer, type RET to update a cell.
#In the minibuffer, revise the cell and type RET to update the object and
# the display.
#If there is a timing problem and the display is not updated,
# then type ^Cv in the spread buffer.
find.sprds <- function(sprdname, reg.names=names(macro(.Registry)))
{
reg.names[find.names(reg.names) == find.names(sprdname)]
}
find.names <- function(reg.names)
{
prn <- parse(text=reg.names)
for (i in 1:length(prn))
if (mode(prn[[i]]) != "name") reg.names[i] <- prn[[i]][[2]]
reg.names
}
print.sprds.emacs <- function(sprdname)
{
fssn <- find.sprds(sprdname)
fssn2 <- fssn
for(i in fssn2) {
fg(i)
print.update.emacs(x.buffer)
}
cat(paste(fssn, collapse="\n"), "\n", sep="", file=.spread.command.file)
invisible(fg(sprdname))
}
print.update.emacs.3d <- function(object)
{
object.name <- as.character(substitute(object))
dobject <- dim(object)
if (length(dobject) != 3) stop("3-way array required")
fg(object.name)
n3 <- dimnames(object)[[3]]
if (is.null(n3)) n3 <- seq(length=dobject[3])
else n3 <- paste("\"", n3, "\"", sep="")
for (i in n3) {
fg(paste( object.name, "[,,", i, "]", sep="" ))
print.update.emacs(x.buffer)
}
invisible(object)
}
emacs.start <- function(spread.directory)
{
assign('.spread.directory', spread.directory, frame=0)
if (!exists('.Registry', 1))
assign(".Registry", where=1, as.spread(matrix(".Registry")))
assign(".spread.command.file", frame=0,
paste(spread.directory, "*command*", sep="/"))
fg(".Registry")
print.update.emacs(.Registry)
invisible(".Registry")
}
print.find.emacs <- function(spread=.Active, update.Registry=T)
{
fg(spread)
if (update.Registry) {
fg(".Registry")
print.update.emacs(.Registry)
fg(spread)
}
print.sprds.emacs(spread)
invisible(spread)
}
emacs.cell <- function(spread, e.r, e.c, result.type)
{
fg(spread)
cell.rc <- cell.rc.emacs(x.buffer, e.r, e.c)
.Options$width <- 1000
if (result.type==1 && cell.rc[1] <= nrow(x.buffer)) {
cell.rc <- cell.sub.emacs(x, cell.rc)
cell.expr <- expr.rc(x, cell.rc)
}
else
cell.expr <- emacs.expr(x, cell.rc, result.type=result.type)
cat(cell.expr, '\n', sep='', file=.spread.command.file)
}
cell.sub.emacs <- function(x, i, j=i[2])
{
# i and j are integer scalars
if (missing(j)) {j <- i[2] ; i <- i[1]}
if (i==0 && j==0) stop("non-zero row or column required")
if ((length(dim(x)) == 2)) {
acpab <- c("","")
positions <- 1:2
}
else if (.Active == .Active.buffer)
stop("Must use rectangular slice, not 3d buffer")
else {
pab <- parse(text=.Active.buffer)
acpab <- as.character( pab[[1]][-(1:2)] )
positions <- (1:length(acpab))[sapply(acpab, nchar) == 0]
}
di <- index.value(dimnames(x)[[positions[1]]], i)
dj <- index.value(dimnames(x)[[positions[2]]], j)
acpab[positions[1]] <- di
acpab[positions[2]] <- dj
acpab
}

View File

@@ -0,0 +1,49 @@
as.grade <- function(x)
{
if (inherits(x,"grade")) return(x)
if (match("sum",dimnames(x)[[2]],0) == 0) {
dx <- dim(x)
dnx <- dimnames(x)
if (length(dim(x)) == 2) {
if (length(dnx) != 2) dimnames(x) <- list(NULL, 1:dx[2])
tmp <- cbind(x,sum=0)
}
if (length(dim(x)) == 3) {
dimnames(x) <- NULL
tmp <- aperm(x,c(1,3,2))
dim(tmp) <- c(dim(tmp)[1]*dim(tmp)[3], dim(tmp)[2])
tmp <- cbind(tmp, sum=0)
dim(tmp) <- (dx + c(0,1,0))[c(1,3,2)]
tmp <- aperm(tmp,c(1,3,2))
if (length(dnx) != 3) dnx <- list(NULL, 1:dx[2], NULL)
dnx[[2]] <- c(dnx[[2]], "sum")
dimnames(tmp) <- dnx
}
if (length(dim(x)) > 3) stop("grade requires 2d or 3d")
}
x <- as.spread(tmp)
sum.col <- match("sum",dimnames(x)[[2]],0)
tmp.expr <- paste(
"x[,",
sum.col,
if (length(dim(x))==3) ",",
"] <- apply(x[,",
-sum.col,
if (length(dim(x))==3) ",",
"],",
deparse(if (length(dim(x))==3) c(1,3) else 1),
",sum)"
)
after(x)["sum"] <- parse(text=tmp.expr)
class(x) <- c("grade", class(x))
update.spread(x)
}
expr.rc.grade <- function(x, acpab)
{
if (sapply(acpab,nchar)[[2]] == 0) {
j <- -match("sum", dimnames(x)[[2]], 0)
acpab[2] <- j
}
expr.rc.default(x,acpab)
}

View File

@@ -0,0 +1,336 @@
;; spreadsheet in S
;; Richard M. Heiberger
;; 1995
;; Load this file from the dired window in which .Data exists.
;; This file does not work with S-mode. Use S-spread.el for S-mode.
(set-variable 'buffers-menu-max-size nil)
(defvar spread-directory (concat "/tmp/" (make-temp-name "spr"))
"Directory in which to store ascii spreadsheet displays.")
(defvar spread-command-file (concat spread-directory "/*command*")
"File through which S will communicate with emacs.")
(defvar spread-directory-p nil
"predicate value non-nil when directory has been defined.")
(defun print-find-emacs nil "display spread.frame from minibuffer" (interactive)
(spread-print-find (read-string "spread.frame: ") t))
(define-key global-map "\C-cr" 'print-find-emacs)
(defun emacs-rc nil "" (interactive)
(emacs-cell "1")
)
(defun emacs-macro nil "" (interactive)
(emacs-cell "2")
)
(defun emacs-macro-control-text nil "" (interactive)
(emacs-cell "4")
)
(defun emacs-macro-print-text nil "" (interactive)
(emacs-cell "5")
)
(defun emacs-cell (result-type) "" (interactive)
(setq spread-name (buffer-name))
(setq r (count-lines 1 (point)))
(setq c (current-column))
(set-buffer S-buffer)
(spread-insert
(format "emacs.cell('%s', %s, %s, %s)"
spread-name r c result-type
)
)
(save-excursion
(set-buffer "*command*")
(revert-t-t)
(goto-char (point-min))
(setq beg (point)) (end-of-line)
(if (equal result-type "4")
(progn
(setq command (buffer-substring beg (point)))
(set-buffer S-buffer)
(spread-insert command)
)
(setq command (read-string "> " (buffer-substring beg (point))))
(set-buffer S-buffer)
(spread-insert command)
(spread-insert "invisible(assign(.Active, x))")
(spread-print-find spread-name nil)
(goto-line r)(forward-char c)
))
)
(defun spread-insert (spread-command) "" (interactive)
(goto-char (point-max))
(insert spread-command)
(comint-send-input)
(accept-process-output spread-process)
)
(defun revert-t-t nil "revert-buffer with no questions asked"
(interactive)
(revert-buffer t t)
)
(defun revert-t-t-read-only nil "revert-buffer, no questions, read-only"
(interactive)
(revert-buffer t t)
(setq buffer-read-only t)
)
(define-key global-map "\C-cv" 'revert-t-t)
(defvar spread-mode-map nil "Keymap for Spread mode.")
(if spread-mode-map
nil
(setq spread-mode-map (make-sparse-keymap))
(define-key spread-mode-map "\C-cv" 'revert-t-t-read-only)
(define-key spread-mode-map "\C-m" 'emacs-rc)
(define-key spread-mode-map "\C-cc" 'emacs-macro)
(define-key spread-mode-map "\C-cs" 'emacs-macro-control-text)
(define-key spread-mode-map "\C-cp" 'emacs-macro-print-text)
(define-key spread-mode-map "f" 'emacs-print-find-emacs)
(define-key spread-mode-map [mouse-2] 'spread-mouse-print-find-emacs)
(define-key spread-mode-map [mouse-3] 'spread-mouse-rc)
;; (define-key spread-mode-map [double-mouse-1] 'spread-mouse-rc) ;doesn't work
(define-key spread-mode-map [menu-bar spread]
(cons "Spread" (make-sparse-keymap "Spread")))
; (define-key spread-mode-map [menu-bar spread spread-macro]
; '("macro" . spread-macro))
(define-key spread-mode-map [menu-bar spread spread-before]
'("before" . spread-before))
(define-key spread-mode-map [menu-bar spread spread-after]
'("after" . spread-after))
(define-key spread-mode-map [menu-bar spread spread-macro]
(cons "Macro" (make-sparse-keymap "sprdtwo")))
(define-key spread-mode-map [menu-bar spread spread-macro display]
'("after" . spread-display))
; (define-key spread-mode-map [mouse-2] 'emacs-menu-print-find-ww)
)
(defun spread-mouse-rc (event) "move point then enter"
(interactive "e")
(mouse-set-point event)
(emacs-rc)
)
(defun spread-mouse-print-find-emacs (event) "move point then find file"
(interactive "e")
(mouse-set-point event)
(emacs-print-find-emacs)
)
(defun spread-mode () "Major mode for spreadsheets.\\{spread-mode-map}"
(interactive)
(kill-all-local-variables)
(make-local-variable 'beg)
(make-local-variable 'command)
(use-local-map spread-mode-map)
(setq mode-name "Spread")
(setq major-mode 'spread-mode)
(if (equal (buffer-name) ".Registry") (spread-highlight-macro))
(setq buffer-read-only t)
)
;; from dired.el L547
; (put-text-property (point)
; (save-excursion
; (dired-move-to-end-of-filename)
; (point))
; 'mouse-face 'highlight)
;
;; (put-text-property (point) (mark) 'mouse-face 'highlight)
(defun spread-highlight-macro nil
"highlight spread.frame names for mouse access"
(interactive)
(save-excursion
(goto-char (point-min))
(search-forward "**macro**")(forward-char)
(toggle-read-only -1)
(while (progn
(setq beg (point))(end-of-line)
(not (= beg (point)))
)
(put-text-property beg (1-(point)) 'mouse-face 'highlight)
(forward-char)
)
(toggle-read-only 1)
)
(save-buffer)
)
(defun emacs-print-find-emacs nil "" (interactive)
(beginning-of-line)
(setq beg (point)) (end-of-line) (backward-char)
(setq spread-name (buffer-substring beg (point)))
(spread-print-find spread-name nil)
)
(defun find-spread-frame-directory nil
"Locate directory in which spread.frame functions are stored."
(list-command-history)
(set-buffer "*Command History*")
(goto-char (point-min))
(search-forward "(load-file ")
(goto-char (1+ (match-end 0)))(setq beg (point))
(end-of-line)(search-backward "/")
(goto-char (match-end 0))
(setq spread-frame-directory
(expand-file-name (buffer-substring beg (point))))
)
(defun inferior-spread-mode ()
"Major mode for running spread.frames under S/Splus."
(comint-run S-program)
(setq comint-prompt-regexp shell-prompt-pattern)
(setq major-mode 'inferior-spread-mode)
(setq mode-name "Inferior Spread")
(setq mode-line-process '(":%s"))
(setq spread-process (get-buffer-process (current-buffer)))
(set-process-filter spread-process 'comint-output-filter)
(set-variable 'comint-output-filter-functions
'(spread-output-filter
comint-postoutput-scroll-to-bottom)
)
(set-variable 'comint-scroll-to-bottom-on-output "this")
(set-variable 'comint-scroll-show-maximum-output t)
(if (not(file-writable-p ".Data/.Audit"))
(accept-process-output spread-process))
(accept-process-output spread-process)
)
(defun spread-output-filter (str)
"detect errors in S output"
(if (or
(string-match "Dumped" str)
(string-match "Error" str)
)
(progn
(switch-to-buffer-other-window S-buffer)
(comint-show-maximum-output)
(set-variable 'quit-flag t); beeps and writes "quit" in the message area
)
)
)
;(put 'spread-region 'menu-enable 'mark-active)
;(put 'spread-validate-region 'menu-enable 'mark-active)
;(put 'spread-print 'menu-enable '(stringp spread-print-file))
;(put 'spread-alt-print 'menu-enable '(stringp spread-print-file))
;(put 'spread-view 'menu-enable '(stringp spread-print-file))
;(put 'spread-recenter-output-buffer 'menu-enable '(get-buffer "*spread-shell*"))
;(put 'spread-kill-job 'menu-enable '(spread-shell-running))
(defun emacs-menu-print-find (spread-name) "" (interactive)
(spread-print-find spread-name nil)
)
(defun spread-print-find (spread-name update-Registry)
"Place SPREAD-NAME in foreground of S-buffer (*S* or *Splus*),
update .Registry and revert buffer when UPDATE-REGISTRY is t,
print all views of spread.frame associated with SPREAD-NAME in .Registry
to /tmp/spr***** directory, and find or revert all views into emacs buffers."
(interactive)
(set-buffer S-buffer)
(spread-insert
(format "print.find.emacs('%s', update.Registry=%s)"
spread-name (if update-Registry "T" "F")))
(if update-Registry
(save-excursion (spread-find-file ".Registry")))
(spread-print-sprds)
(switch-to-buffer spread-name)
)
(defun spread-print-sprds () "Display in buffers all views of spread.frame"
(interactive)
(save-excursion
(set-buffer "*command*")
(revert-t-t)
(goto-char (point-min))
(while (< (point) (point-max))
(set-buffer "*command*")
(setq beg (point)) (end-of-line)
(setq spread-name-i (buffer-substring beg (point)))
(save-excursion (spread-find-file spread-name-i))
(forward-line)))
)
(defun spread-find-file (spread-name) "Display one view of spread.frame"
(interactive)
(switch-to-buffer spread-name)
(if (buffer-file-name)
(revert-t-t-read-only)
(kill-buffer spread-name)
(find-file (concat spread-directory "/" spread-name))
)
(spread-mode)
)
(define-key spread-mode-map [menu-bar spread ww]
'("ww" . emacs-menu-print-find-ww))
(defun emacs-menu-print-find-ww () "" (interactive)
(emacs-menu-print-find "ww"))
(define-key spread-mode-map [menu-bar spread ww2]
'("ww2" . "\e\e (emacs-menu-print-find \"ww\")"))
(define-key spread-mode-map [menu-bar spread ww3]
'("ww3" . "\M-x eval-expression\C-m (emacs-menu-print-find \"ww\")"))
(defun spread-start () "load emacs spread.frame handler"
(if (not (equal major-mode 'dired-mode)) (set-variable 'quit-flag t))
(setq spread-home-directory (dired-current-directory))
(find-spread-frame-directory)
(kill-buffer "*Command History*")
(if (not spread-directory-p)
(progn (make-directory spread-directory)
(setq spread-directory-p t)))
(setq S-program (read-string "Splus or S? " "Splus"))
(setq S-buffer (concat "*" S-program "*"))
(if (not (get-buffer S-buffer))
(get-buffer-create S-buffer))
(if (get-buffer-process S-buffer) (set-variable 'quit-flag t))
(set-buffer S-buffer)
(cd spread-home-directory)
(inferior-spread-mode)
(spread-insert
(format "attach('%s.Data')" spread-frame-directory))
(spread-insert
(format "emacs.start('%s')" spread-directory))
(find-file spread-command-file)
(spread-find-file ".Registry")
)
;; start it up
(spread-start)

View File

@@ -0,0 +1,329 @@
#-*-Fundamental-*-
# Spreadsheet written in S
# The spreadsheet may be called anything.
# References to cells in the spreadsheet must be called "x".
# Updating is in column order.
# Version 3 classes and methods technology.
as.spread <- function(x)
{
if (is.spread(x)) return(x)
x <- as.array(x)
attr(x,"expr") <- as.expr(x, length=0)
attr(x,"macro") <- as.expr(x, length=0)
attr(x,"before") <- as.expr(x, length=0)
attr(x,"after") <- as.expr(x, length=0)
class(x) <- c("spread", class(x))
x
}
is.spread <- function(x)
inherits(x,"spread")
print.spread <- function(x, ..., quote=F)
{
if (inherits(x, "data.frame")) print.data.frame(x)
else {
class(x) <- class(x)[-match("spread",class(x))]
print.array(x, ..., quote=quote)
}
invisible(x)
}
"[.spread"<-
function(x, ..., drop = F)
{
# Note: We do not retain the spread class!
# If we did, the subscripts on the expr() and macros() would be wrong
#
NextMethod("[", drop=drop)
}
"[.expr" <- function(x, ... , drop=F)
{
# Note: We do retain the expr class.
# The primary use is for printing, so we want the original subscripting.
z <- NextMethod("[", drop=drop)
class(z) <- class(x)
z
}
update.spread <- function(object, ..., force=F)
{
if (force) object <- eval.spread(object, NULL, force=force)
if (length(before(object)))
object <- eval.spread(object, before(object))
if (length(expr(object)))
object <- eval.spread(object, force=force)
if (length(after(object)))
object <- eval.spread(object, after(object))
object
}
eval.spread <- function(object, e, force=F)
{
x <- object
class(x) <- class(x)[-match("spread",class(x))]
if (force) {
.Options$warn <- -1
tmp <- as.numeric(as.matrix(x))
if (!any(is.na(tmp))) x <- tmp
}
if (missing(e)) {
if (inherits(x,"data.frame")) {
e <- expr(object)
if (force)
for (j in 1:ncol(x)) for (i in 1:nrow(x))
x[[i,j]] <- eval(e[i,j])
else
for (j in 1:ncol(x)) for (i in 1:nrow(x)) {
eij <- e[i,j]
if(is.language(eij)) x[[i,j]] <- eval(eij)
}
}
else {
i <- 0
if (force)
for (ei in expr(object))
{i <- i+1; x[i] <- eval(ei)}
else
for (ei in expr(object))
{i <- i+1; if(is.language(ei)) x[i] <- eval(ei)}
}
}
else eval(e)
class(x) <- class(object)
x
}
#usage: x <- macro.eval(x, i)
macro.eval <- function(object, i)
eval.spread(object, macro(x)[i])
"[[<-.spread" <- function(...) do.call("[<-.spread", list(...))
"[<-.spread" <- function(object, ..., value)
{
x <- object
expr(x) <- expression()
class(x) <- NULL
e <- expr(object)
l.e <- length(e)
i.a.v <- is.atomic(substitute(value))
n.cells <- prod(dim(x[..., drop=F]))
if (l.e == 0) {
if (n.cells != 1 || i.a.v )
x[...] <- eval(substitute(value))
else {
e <- as.expr(object)
l.e <- length(e)
}
}
if (l.e != 0) {
if (n.cells != 1) {
e.s.v <- eval(substitute(value, sys.parent()))
x[...] <- e.s.v
e[...] <- e.s.v
}
else {
e[[...]] <- substitute(value)
x[[...]] <- eval(e[[...]])
}
}
attributes(x) <- attributes(object)
class(x) <- class(object)
expr(x) <- e
update.spread(x)
}
print.expr <- function(e, ..., replace.string=F) {
replace <- as.logical(replace.string)
if (length(e) == 0) {
if (replace) cat(replace.string, "<- ")
print(expression())
}
else if (is.null(dim(e))) {
ne <- names(e)
for (i in 1:length(e)) {
nei <- index.value(ne, i)
if (replace) cat(replace.string)
cat(paste("[", nei, "] ", sep=""))
if (replace) cat("<- expression(")
cat(e[i])
if (replace) cat(")")
cat("\n")
}
}
else {
dn <- dimnames(e)
if (is.null(dn)) dn <- list()
for (i in 1:length(dim(e))) {
if (is.null(dn[[i]])) dn[[i]] <- 1:dim(e)[i]
}
dnn <- outer(dn[[1]], dn[[2]], paste, sep=",")
if (length(dn) > 2)
for (i in 3:length(dn))
dnn <- outer(dnn, dn[[i]], paste, sep=",")
for (i in seq(length=length(e))) {
if (replace) cat("x")
cat(paste("[", dnn[i], "] ", sep=""))
if (replace) cat("<-")
cat(paste(" ", e[i], "\n", sep=""))
}
}
invisible(e)
}
as.expr <- function(x, ...) UseMethod("as.expr")
as.expr.default <- function(x, length.x=prod(dim(x))) {
e <- vector(mode="expression", length=length.x)
x <- unclass(x)
if (length.x > 0) {
e <- array(e, dim(x), dimnames(x))
e[] <- x[]
# for (i in 1:length(e)) e[i] <- x[i]
}
class(e) <- "expr"
e
}
as.expr.data.frame <- function(x, length.x=prod(dim(x))) {
e <- vector(mode="expression", length=length.x)
if (length.x > 0) {
e <- array(e, dim(x), dimnames(x))
u.x <- unclass(x)
for (j in 1:ncol(x)) {
uxj <- as.matrix(u.x[[j]])
for (i in 1:nrow(x))
e[i,j] <- uxj[i,1]
}
}
class(e) <- "expr"
e
}
expr <- function(x)
attr(x,"expr")
# "expr<-" is used only when value is a matrix the size of x, or to update
# a subscripted piece of x. It is not a user function.
# Currently used only in "[<-.spread".
"expr<-" <- function(x, value)
{
attr(x,"expr") <- value
x
}
"before<-" <- function(x, value)
{
attr(x,"before") <- value
class(attr(x,"before")) <- "expr"
x
}
"macro<-" <- function(x, value)
{
attr(x,"macro") <- value
class(attr(x,"macro")) <- "expr"
x
}
"after<-" <- function(x, value)
{
attr(x,"after") <- value
class(attr(x,"after")) <- "expr"
x
}
before <- function(x)
attr(x,"before")
macro <- function(x)
attr(x,"macro")
after <- function(x)
attr(x,"after")
expr.rc <- function(x, ...) UseMethod("expr.rc")
expr.rc.default <- function(x, acpab)
{
subs <- paste("[", paste(acpab, collapse=","), "]")
if (length(expr(x))==0) {
x.expr <- paste("x.value(x",subs,")",sep="")
value <- eval(parse(text=x.expr))
}
else {
e.expr <- paste("expr.value(expr(x)", subs, ", x", subs, ")")
value <- eval(parse(text=e.expr))
}
paste("x", subs, " <- ", value, sep="")
}
x.value <- function(x) {
value <-
if (length(x)==1)
as.vector(as.matrix(x[[1]]))
else if (inherits(x,"data.frame"))
lapply(x, function(x) as.vector(as.matrix(x)))
else
as.vector(x)
deparse(value)
}
expr.value <- function(e, x) {
if (inherits(x,"data.frame") &&
(dim(e)[2]>1 || inherits(x[[1]],"factor")))
value <- deparse(lapply(e, function(x) as.vector(as.matrix(x))))
else {
value <- paste(e, collapse=",")
if (length(e) > 1) value <- paste("c(", value, ")", sep="")
}
value
}
index.value <- function(dn, i, deparse.result=T) {
if (i==0) {i <- 0; mode(i) <- "missing"}
if (is.numeric(i) && i>0 && length(dn)) i <- dn[i]
if (deparse.result) deparse(as.vector(i))
else as.vector(i)
}
as.numeric.spread <- function(x)
{
.Options$warn <- -1
tmp <- as.numeric(unclass(x))
tmp <- ifelse(is.na(tmp), 0, tmp)
attributes(tmp) <- attributes(x)
tmp
}
all.numeric <- function(x) {
.Options$warn <- -1
!any(is.na(as.numeric(x)))
}

View File

@@ -0,0 +1,114 @@
# prspread is based on prmatrix
prspread <-
function(x, rowlab = character(0), collab = character(0), quote = T, right = F,
spread.name=deparse(match.call()[["x"]]) )
{
d <- dim(x)
dnames <- dimnames(x)
if(is.null(dnames))
dnames <- list(rowlab, collab)
else {
if(!missing(rowlab))
dnames[[1]] <- as.character(rowlab)
if(!missing(collab))
dnames[[2]] <- as.character(collab)
}
if(length(dnames[[1]]) == 0)
dnames[[1]] <- paste("[", 1:d[1], ",]", sep = "")
else if(length(dnames[[1]]) != d[1])
stop("rowlab is wrong length")
if(length(dnames[[2]]) == 0)
dnames[[2]] <- paste("[,", 1:d[2], "]", sep = "")
else if(length(dnames[[2]]) != d[2])
stop("collab is wrong length")
cbind(c(spread.name,dnames[[1]]), rbind(dnames[[2]], as.matrix(x)))
}
row.ch <- function(x, d=dim(x))
array(1:d[1], d, dimnames(x))
col.ch <- function(x, d=dim(x))
array(rep.int(1:d[2], rep.int(d[1], d[2])), d, dimnames(x))
print.text <- function(x, screen.n, cex=1,
spread.name=deparse(match.call()[["x"]]), clear=T, ...)
{
x.pr <- prspread(x, spread.name=spread.name)
if (!missing(screen.n)) screen(screen.n)
usr <- c(0, ncol(x.pr), 0, nrow(x.pr)) - .5
par(usr=usr)
par(plt=c(0,1,0,1))
if (clear)
polygon(usr[c(1,2,2,1)],usr[c(3,3,4,4)], den=-1,col=0,xaxt="s",yaxt="s")
text(x=as.vector(col.ch(x.pr)-1),
y=as.vector(nrow(x.pr)-row.ch(x.pr)), x.pr, cex=cex, ...)
box()
invisible(x)
}
text.update.spread <- function(xij, row.i, col.j, screen.n, cex=1, x)
{
if (!missing(screen.n)) {screen(screen.n, new=F); par(plt=c(0,1,0,1))}
y <- nrow(x)-row.i
clear.text(x=col.j, y=y)
text(x=col.j, y=y, xij, cex=cex)
box()
invisible(x)
}
cell.rc.text <- function(nrow.x, n=1, type="n")
{
xy <- locator(n, type)
c(row=nrow.x-round(xy$y), col=round(xy$x))
}
clear.text <- function(x,y)
polygon(x-.5+c(0,1,1,0), y-.5+c(0,0,1,1), den=-1, col=0, border=F,
xaxt="s", yaxt="s")
print.update.text <- function(x, ..., x.old, screen.n, cex=1,
spread.name=deparse(match.call()[["x"]]))
{
if(missing(x.old)) return(invisible(print.text(x, screen=screen.n,
cex=cex, spread.name=spread.name)))
if (!missing(screen.n)) {screen(screen.n, new=F); par(plt=c(0,1,0,1))}
diff.x <- as.vector(x != x.old)
xx <- col(x)[diff.x]
yy <- nrow(x)-row(x)[diff.x]
for (i in seq(along=xx)) clear.text(xx[i], yy[i])
box()
text(x=xx, y=yy, as.vector(unlist(x))[diff.x], cex=cex)
invisible(x)
}
control.text <- function(x, screen.n, cex=1,
spread.name=deparse(match.call()[["x"]]))
{
#This is a real function that does its own work
if (!missing(screen.n)) {screen(screen.n, new=F); par(plt=c(0,1,0,1))}
x.old <- x[,]
rc <- cell.rc.text(nrow(x))
command <- expr.rc(x, rc)
cat("> ", command, "\n", sep="", file="")
eval(parse(text=readline()))
if (!missing(screen.n)) {screen(screen.n, new=F); par(plt=c(0,1,0,1))}
print.update.text(x, x.old=x.old, cex=cex, spread.name=spread.name)
# print.text(x, cex=cex, spread.name=spread.name)
invisible(x)
}
#text usage
# device() # for example, x11(), or motif(), or win.graph()
# x <- my.spread # copy my.spread to x
##loop
# print.text(x) # work with x
# x <- control.text(x, screen) # screen is optional
##end loop
# my.spread <- x # copy revised x back to my.spread

View File

@@ -0,0 +1,197 @@
The emacs spread.frame device handler
Richard M. Heiberger
There are two variants in the usage of this emacs spread.frame device
handler. Both use the same command file: S-spread.el. One variant is
stand-alone. The other works with S-mode. Both are written in emacs
19.29 to use the comint.el package. They will not work in emacs 18.
A. Stand-alone Usage
1. Create a .Data subdirectory in the directory you will be using, say
`myclass' and `myclass/.Data'. Get into the dired buffer of the
directory `myclass'. Any other buffer will cause the terminal to beep.
2. From the dired buffer enter (on my computer):
M-x load-file <RET> /disk5/rmh/sprd3d/S-spread.el
Edit the pathname for your computer. Any other buffer than the dired
buffer will cause the terminal to beep. You will be prompted "S or
Splus? ". "Splus" has been filled in as the default. Edit the
command name if necessary, inserting a full pathname if appropriate,
then hit carriage return.
This leaves the window showing the .Registry buffer in Spread mode. If
you previously had a .Registry in that directory, it appears in the
buffer. If you have never used the spread.frame handler in that
directory, then a new .Registry has been created for you.
You also have a buffer called *Splus* (or *S*) in Inferior Spread mode
in which Splus (or S) is running.
NOTES for Stand-alone Version
If you were previously running Splus in buffer *Splus* in Inferior Spread mode
and accidentally killed the Splus process (for example, with the q()
command), you are still using that buffer and the Splus process has been
restarted.
If you have a buffer named *Splus* not associated with a process, for
example a file you are editing, emacs will use that buffer for the
Inferior Spread mode.
If you have a running Inferior Spread process, a shell process, or any
other process, in a buffer named *Splus*, the terminal will beep.
B. S-mode Usage
1. Create a .Data subdirectory in the directory you will be using, say
`myclass' and `myclass/.Data'. Get into the dired buffer of the
directory `myclass' and start S-mode with M-x S.
2. From the *S* buffer that S-mode has started enter (on my computer):
M-x load-file <RET> /disk5/rmh/sprd3d/S-spread.el
Edit the pathname for your computer. Any other buffer than the *S* buffer
will cause the terminal to beep.
This leaves the window showing the .Registry buffer in Spread mode.
If you previously had a .Registry in that directory, it appears in the
buffer. If you have never used the spread.frame handler in that
directory, then a new .Registry has been created for you.
NOTES FOR BOTH VERSIONS
S/Splus thinks it is in charge and does not know about emacs. Emacs with
comint attempts to coordinate its timing with Splus by sending commands to
Splus with (comint-send-input) and waiting for their completion with
(accept-process-output). If for any reason an out-of-date display of a
buffer appears, use ^Cv to bring up the current display. If things
still look wrong, go to the *Splus* buffer and force a current display
with ^Cr. You will be requested to type the name of the object to be
displayed in the minibuffer. All buffers displaying views of that
object, and the .Registry buffer will be updated.
Either usage of the spread.frame functions and the command file
S-spread.el works with S Version 3, S Version 4, or Splus 3.3.
3. Start working in the .Registry buffer. Move to the macro section.
a. Do "f" or [mouse-2] on the name of the spread.frame you want to see.
Spread.frame names are listed in the macro section of the display.
b. If no names appear, then you must add them.
4. To add more spread.frames, for example the "xy" spread.frame, where the
"xy" spread.frame already exists in the .Data:
a. Move to the *Splus* buffer. Enter "^Cr".
b. The minibuffer will ask you for the name of a spread.frame.
c. Enter the name of the object (for example xy (no quotes))
or an expression for a 2-way rectangular slice (xy[,,2]) of a 3-way object.
d. The "xy" spread.frame will appear in the buffer.
5. To add a three-way spread.frame to the display from the *Splus* buffer
a. Create a 3-way array and make it a spread.frame:
xs <- as.spread(array(1:12,dim=c(2,3,2)))
b. Print it to the /tmp/spraxxxxx directory with:
print.update.emacs.3d(xs)
c. Move the cursor to the .Registry buffer. Place the cursor on the
.Registry entry and press RETURN twice. The names for the slices
will now appear in the **macro** section (if not, use ^Cv).
d. Place the cursor on each of the slices' names and press f.
e. The entire spread.frame can also be displayed by pressing "f"
or [mouse-2] on its name.
The window displaying the entire spread.frame is not active.
Pressing RETURN will beep.
f. The slices are active. Pressing RETURN on a cell entry will update
the entire spread.frame and the display of the slices. Pressing RETURN
on a macro keyword or a macro name in a slice buffer will activate the
display and update of the macro for the entire spread.frame.
6. Move between spread.frames with ^X o.
7. To edit a spread.frame, place the cursor on a cell and press ENTER
or [mouse-3]. The expression associated with the cell will be
displayed in the mini-buffer. Edit it and press ENTER. The
spread.frame in Splus will be updated, and all views of the object in
emacs buffers will be updated.
8. To execute a macro, place the cursor on the macro name and enter ^Cc.
Don't use print() or cat() in macros; sink() is in use.
The graphics device can be used for rectangular spread.frames, but does
not yet work with three-way spread.frames.
To use a graphics device for the spread.frame display (but no macros yet).
9. Open a graphics device: x11(), iris4d(), motif(), etc.
10. Add the names of the spread.frames to .Registry as described above.
11. To place a spread.frame in the graphics device, put the cursor on the
spread.frame name in the **macro** listing in .Registry, and press ^Cp
The minibuffer will display
> xy <- print.text( xy )
Press ENTER and the device will show the xy spread.frame.
12. To change a value in a spread.frame in the graphics device, put the
cursor on the spread.frame name in the **macro** listing in .Registry,
and press ^Cs
The minibuffer will display
> xy <- control.text( xy )
Press ENTER, move the cursor into the graphics window, and click when the
crosshair is on the cell you wish to change. Place the cursor in the *Splus*
buffer, move to the end of the buffer by pressing ESC > . You will see
the expression to be edited (prefixed with a ">") on the next to the last
line. Move the cursor to that line, edit the value, and press ENTER.
The graphics window will be updated.
13. You can edit any emacs buffer spread.frame by switching to its
buffer and pressing ENTER or [mouse-3] on the appropriate entry. You
can edit any spread.frame in the graphics device, by switching to the
.Registry buffer, confirming that the spread.frame is in the graphics
window (or putting it there with ^Cp), and then entering ^Cs on the
macro name in the .Registry buffer that matches the spread.frame.
14. There is an additional feature in the spread.frame interface that
is very useful for numerical rows or columns. When the cursor is
placed on the dimnames row or column, the entire column or row is made
available in the mini-buffer. Warning: expr() in the row or column
will be evaluated and will no longer be expr().
15. Character data. Character matrices work well as spread.frames.
16. Warning: character or factor columns in data.frames.
S likes to coerce character columns in data.frames to factors.
Updating an entire factor column, or an entire row containing factor
columns, may be dangerous because the revised values may not be in the
levels(). The entire column may be replaced with NA values. Updating
of individual character values is fine in character arrays that are
not data.frames, or in data.frames where the length(expr(x)) ==
prod(dim(x)). To get a character column into a data frame use
my.frame$char <- character.value # remains character
Using either
my.frame[,"char"] <- character.value # coerced to factor
my.frame <- cbind(my.frame,character.value) # coerced to factor
won't work. Either of those forms coerces the values to factor.

View File

@@ -0,0 +1,2 @@
modify the test with a change.
SJE: simple change.