SimplePlotHack.mesa
Last Edited by: SChen, June 15, 1985 7:37:41 pm PDT
DIRECTORY
Basics USING [LowHalf],
BasicTime USING [Now],
Commander USING [CommandProc, Register],
CommandTool USING [ParseToList],
Convert USING [CardFromRope, Error],
FileNames USING [CurrentWorkingDirectory],
FS USING [ComponentPositions, EnumerateForNames, ExpandName, NameProc, Error, StreamOpen],
IO USING [Close, EndOfStream, Error, GetCard, GetReal, GetRopeLiteral, int, PutFR, STREAM],
List USING [DReverse],
Plot USING [AddVector, CreateViewer, PlotSpec, PlotSpecRec, RealSequence, RopeSequence, Vector],
Rope USING [Cat, Equal, Fetch, Find, IsEmpty, Length, ROPE, Substr],
ViewerClasses USING [Viewer];
 
SimplePlotHack: 
CEDAR 
PROGRAM
IMPORTS Basics, BasicTime, Commander, CommandTool, Convert, FileNames, FS, IO, List, Plot, Rope = {
OPEN IO, Plot;
RopeList: TYPE = LIST OF Rope.ROPE;
DataError: SIGNAL[reason: Rope.ROPE ← NIL] = CODE;
SPlot: Commander.CommandProc = {
argList: RopeList;
length: NAT;
[argList, length] ← CommandTool.ParseToList[cmd];
IF length <= 0 THEN msg ← "To plot data in files, type: SPlot <files>"
ELSE {
wDir: Rope.ROPE ← FileNames.CurrentWorkingDirectory[];
nPlots: NAT ← 0;
maxPlots: NAT ← 12;
allVersions: BOOL ← FALSE;
FOR arg: RopeList ← argList, arg.rest 
UNTIL arg = 
NIL 
OR msg # 
NIL 
DO
IF arg.first.Fetch[0] = '- 
THEN {
IF arg.first.Length[] >= 2 
THEN 
SELECT arg.first.Fetch[1] 
FROM
'A, 'a => allVersions ← TRUE;
'H, 'h => allVersions ← FALSE;
IN ['0..'9] => {
max: 
NAT ← Convert.CardFromRope[arg.first.Substr[1]
! Convert.Error => max ← maxPlots]; -- don't change it
maxPlots ← max;
};
 
ENDCASE; -- simply ignors illegal switches
 
}
 
ELSE {
fileList: RopeList ← FileListFrom[arg.first, wDir, allVersions];
FOR file: RopeList ← fileList, file.rest 
UNTIL file = 
NIL 
OR msg # 
NIL 
DO
msg ← 
IF nPlots >= maxPlots 
THEN
IO.PutFR["Note: max. %g plots for each command.", IO.int[maxPlots]]
ELSE SimplePlot[file.first, nPlots # 0];
nPlots ← nPlots + 1;
ENDLOOP;
 
};
 
ENDLOOP;
 
};
 
}; -- SPlot
FileListFrom: 
PROC [pattern, wDir: Rope.
ROPE ← 
NIL, allVersions: 
BOOL ← 
FALSE] 
RETURNS [fileList: RopeList ← 
NIL] = {
root, lastRoot: Rope.ROPE ← NIL;
LinkIt: 
FS.NameProc 
-- 
PROC [fullFName] 
RETURNS [continue: 
BOOL] -- = {
excl: INT ← fullFName.Find["!"];
continue ← TRUE;
IF fullFName.Substr[excl-6, 6].Equal[".press", FALSE] THEN RETURN;
IF ~allVersions 
THEN {
root ← fullFName.Substr[0, excl];
IF root.Equal[lastRoot, 
FALSE] 
THEN {
fileList.first ← fullFName;
RETURN;
};
 
lastRoot ← root;
};
 
fileList ← CONS[fullFName, fileList];
}; -- LinkIt
FS.EnumerateForNames[pattern, LinkIt, wDir];
TRUSTED {fileList ← LOOPHOLE[List.DReverse[LOOPHOLE[fileList]]]};
}; -- FileListFrom
 
SimplePlot: 
PROC[file: Rope.
ROPE ← 
NIL, iconic: 
BOOL ← 
TRUE]
RETURNS[msg: Rope.ROPE ← NIL] = {
s: IO.STREAM ← NIL;
ok: BOOL ← TRUE;
fullName, status: Rope.ROPE ← NIL;
IF file.IsEmpty[] THEN RETURN["No file name."];
[fullName, ]← FS.ExpandName[file, FileNames.CurrentWorkingDirectory[]];
s ← FS. StreamOpen[fullName ! FS.Error => {status ← error.explanation; ok ← FALSE; CONTINUE} ];
IF ok 
THEN {
ENABLE {
DataError => {
msg ← reason;
CONTINUE;
};
IO.EndOfStream => {
msg ← Rope.Cat["End of file reached", status];
CONTINUE;
};
 
IO.Error => {
msg ← Rope.Cat[
SELECT ec 
FROM
SyntaxError => "Syntax error",
Overflow => "Overflow in input conversion"
ENDCASE => IO.PutFR["IO Error # %g", IO.int[LOOPHOLE[ec, CARDINAL]]],
 
status];
CONTINUE;
};
 
ABORTED => {
msg ← "SPlot aborted. ... ";
CONTINUE;
};
 
};
 
set plotSpec
viewer: ViewerClasses.Viewer;
nVector: CARDINAL;
plotSpec: PlotSpec ← 
NEW[PlotSpecRec ← [
file: fullName,
time: BasicTime.Now[]
]];
status ← " in getting the title.";
plotSpec.title ← s.GetRopeLiteral[];
status ← " in getting xmin.";
plotSpec.bounds.xmin ← s.GetReal[];
status ← " in getting ymin.";
plotSpec.bounds.ymin ← s.GetReal[];
status ← " in getting xmax.";
plotSpec.bounds.xmax ← s.GetReal[];
status ← " in getting ymax.";
plotSpec.bounds.ymax ← s.GetReal[];
IF plotSpec.bounds.xmin > plotSpec.bounds.xmax 
THEN
SIGNAL DataError["Found xmin > xmax"];
 
IF plotSpec.bounds.ymin > plotSpec.bounds.ymax 
THEN
SIGNAL DataError["Found ymin > ymax"];
 
status ← " in getting the number of curves.";
plotSpec.nCurvesMax ← Basics.LowHalf[s.GetCard[]];
plotSpec.legendEntries ← NEW[RopeSequence[plotSpec.nCurvesMax]];
FOR i: 
CARDINAL 
IN [0..plotSpec.nCurvesMax) 
DO
status ← IO.PutFR[" in getting the name for curve #%g.", IO.int[i+1]];
plotSpec.legendEntries[i] ← s.GetRopeLiteral[];
ENDLOOP;
 
status ← " in getting the number of rows.";
nVector ← Basics.LowHalf[s.GetCard[]];
viewer ← CreateViewer[spec: plotSpec, iconic: iconic];
FOR i: 
CARDINAL 
IN [0..nVector) 
DO
vector: Vector ← NEW[RealSequence[plotSpec.nCurvesMax + 1]];
FOR j: 
CARDINAL 
IN [0..plotSpec.nCurvesMax] 
DO
ENABLE {
IO.Error => {
msg ← Rope.Cat[
SELECT ec 
FROM
SyntaxError => "Syntax error",
Overflow => "Overflow"
ENDCASE => IO.PutFR["IO Error # %g", IO.int[LOOPHOLE[ec, CARDINAL]]],
 
IO.PutFR[" in getting the %g-th number on the %g-th row in the table.",
IO.int[j+1], IO.int[i+1]]];
 
GOTO exit;
};
 
IO.EndOfStream => {
msg ← Rope.Cat[
"End of file reached",
IO.PutFR[" in getting the %g-th number on the %g-th row in the table.",
IO.int[j+1], IO.int[i+1]]];
 
GOTO exit;
};
 
};
 
vector[j] ← s.GetReal[];
ENDLOOP;
 
AddVector[viewer, vector];
ENDLOOP;
 
};
 
IF s # NIL THEN s.Close[];
}; -- SimplePlot
 
Commander.Register[
"SPlot", SPlot,
"SPlot <data files>, use a simple minded plot routine to plot data in the data files that have the following special format:
-- comment nodes are ignored.
-- carriage returns are treated the same as spaces.
<title> -- a text string enclosed by double quotes.
<xmin> <ymin> <xmax> <ymax> -- four real numbers.
<number of curves> -- Curves are functions of x.
<names of the curves> -- Each name is a text string enclosed by double quotes.
<number of rows>
-- Each row in the table below has a leading x value followed by the corresponding y values.
-- If there are n curves then the table for m different x values will be an m x n+1 matrix as follows.
x1  y1(x1)  y2(x1)  y3(x1)  ...  yn(x1)
x2  y1(x2)  y2(x2)  y3(x2)  ...  yn(x2)
... ... ... ... ... ... ... ... ... ... ... ... ... ... 
xm  y1(xm)  y2(xm)  y3(xm)  ...  yn(xm)
"];
}.