Thanks Joe,
your help has been invaluable. These regular expressions have a regularity that is difficult to grasp. I would not have got very far without your examples. The help page on Regular expressions was, well, regular, but I learned more from your examples. I came across this page, which clarified a thing or two, http://www.regular-expressions.info/charclass.html, but by and large the whole business of these regexps (allow me to use the jargon) remains a mystery to me.
I got most of what I wanted to work. But I had to work hard. Consider, for instance,
(\2610.01) dup 0 stringbbox 1156
I believe I had to write this to catch it:
str := StringTools:-RegSubs("(\n\\(\\\\[0-9]+.[0-9]+\\)) (dup 0 stringbbox [0-9]+)"
= "\\1 Label \\3", str);
You had warned me, it takes some tricky escaping and backslashing and whathaveyou. I was quite surprised when the 4 backslashes worked, wow. But is it art? ;-)
In the process, I have learned a bit about postscript.
I have managed to produce 3D postscript images that look much better than the jpegs. By tweaking the fonts and the thickness of the axes and of the lines, I've been able to make them very nearly consistent in look and feel. The fonts don't look quite as sharp though. But that's really because the 2D postscript images obtained by the standard gui are excellent. Looking inside the postscript file is interesting: the 2D standard gui postscript plot driver produces files that contain font definitions and lots of other things, very well organized and easy to understand, while the 3D classic gui postscript plot driver produces files that are quite minimal and harder to understand.
I really hope Maple 16 will surprise me with a rewritten 3d postscript plot driver!
My image now has gone down from 11,226,123 bytes to 295,443 bytes! Quite an achievement. And considering that I have a few hundred, the gain in space is non-negligeable too!
It would have been good to control the thickness of the plot lines and of the boxed axis separately, as they are currently all controlled by the "medium" keyword. It's not completely impossible to do, but it's very plot-specific, so I haven't bothered.
I'm quite satisfied with the results. Thanks a lot for your help and guidance. I enjoyed the learning process too.
For the record, here are the revised procedures I have used to produce and fix the plots. Step 1: CleanPlot (see above). Step 2 : MakeMPL (see above). Step 3 : FixMPL (see below). Step 4: MakeEPS (see above). Step 5: EditEPS (see below).
FixMPL := proc( mplfile :: string )
description "cmaple can only handle orientation = [theta,phi], if a third option is given, orientation = [theta,phi,psi], cmaple may fail to produce an eps";
uses FT = FileTools, ST = StringTools;
local str;
str := FT:-Text:-ReadFile(mplfile);
fclose(mplfile);
str := ST:-RegSubs("(ORIENTATION\\([0-9.+-]+,[0-9.+-]+),[0-9.+-]+\\)"="\\1)",str);
FT:-Text:-WriteString(mplfile, str);
fclose(mplfile);
end proc:
EditEPS := proc( epsfile :: string
, { thin :: posint := 10 } # defined by cmaple
, { medium :: posint := 20 } # defined by cmaple
, { thick :: posint := 30 } # defined by cmaple
, { [SymbolThickness,symbolthickness] :: posint := 50 }
, { [CurvesThickness,curvesthickness] :: posint := 33 }
, { [AxesThickness,axesthickness] :: posint := 16 }
, { [Margin,margin] :: integer := 10 }
, { [DrawBorder,drawborder] :: string := "false" }
, { [BoundaryThickness,BorderThickness,boundarythickness,borderthickness] :: integer := 20 }
, { [DefaultFontType,defaultfonttype] :: string := "Times-Roman" }
, { [DefaultFontScale,defaultfontscale] :: posint := 120 }
, { [DefaultTitleFontType,defaulttitlefonttype] :: string := "Times-Roman-Bold" }
, { [DefaultTitleFontScale,defaulttitlefontscale] :: posint := 220 }
, { [AxisLabelFontType,labelfont] :: string := "Times-Italic" }
, { [AxisLabelFontScale,labelscale] :: posint := 180 }
, { [TickLabelFontType,tickfont] :: string := "Times-Roman" }
, { [TickLabelFontScale,tickscale] :: posint := 140 }
, { ext :: string := ".eps" }
, { dir :: string := cat(currentdir(),kernelopts(dirsep)) }
)
local str, llx, lly, urx, ury, all, bb, regex;
uses FT = FileTools, ST = StringTools;
### Modify the generated postscript file
str := FT:-Text:-ReadFile(cat(dir,convert(epsfile,string),ext));
fclose(cat(dir,convert(epsfile,string),ext));
if is(ST:-Search("Patrick",str)=0) then
str := ST:-RegSubs("Creator: Maple" = "Creator: Maple with cmaple and Patrick", str);
else
error("plot already fixed! re-run MakeEPS to create and edit a new postscript file");
end if;
# cmaple assigns keyword "thin" to axis tickmark thickness
str := ST:-RegSubs("\n/thin ([0-9]+) def" = sprintf("\n/thin %d def", thin), str);
# cmaple assigns keyword "medium" to both curves thickness and axis line thickness
str := ST:-RegSubs("\n/medium ([0-9]+) def" = sprintf("\n/medium %d def", medium), str);
# cmaple defines but does not use keyword "thick"
str := ST:-RegSubs("\n/thick ([0-9]+) def" = sprintf("\n/thick %d def", thick), str);
# new keyword "SymbolThickness" has been mapped to the lines that create the point symbol, if any
str := ST:-RegSubs("(\n/thick ([0-9]+) def\n)" = sprintf("\\1/SymbolThickness %d def\n/CurvesThickness %d def\n/AxesThickness %d def\n", SymbolThickness, CurvesThickness, AxesThickness), str);
# keyword "DrawBorder" may be set to true or false
str := ST:-RegSubs("drawborder true def" = sprintf("drawborder %s def",DrawBorder), str);
str := ST:-RegSubs("drawborder false def" = sprintf("drawborder %s def",DrawBorder), str);
# keyword "BoundaryThickness" controls border thickness, if any
str := ST:-RegSubs("\n/boundarythick ([0-9]+) def" = sprintf("\n/boundarythick %d def", BoundaryThickness), str);
# replace the default Helvetica font by the Times font and "embed" it
str := ST:-RegSubs("(IncludeResource: font) (Helvetica)" = "\\1 Times", str);
str := ST:-RegSubs("(DocumentNeededResources: font) (Helvetica)" = "\\1 Times", str);
# Define /TickLabelFont and /AxisLabelFont
# A typical default set-up produced by cmaple is:
# /defaultTitleFont {/Helvetica findfont 256 scalefont setfont} def
# /defaultFont {/Helvetica findfont 156 scalefont setfont} def
# new keywords "DefaultFontType", "DefaultFontScale",
# new keywords "AxisLabelFontType", "AxisLabelFontScale",
# new keywords "TickLabelFontType", "TickLabelFontScale"
# first step, define AxisLabelFont and TickLabelFont
str := ST:-RegSubs("(\n/defaultFont {/Helvetica findfont ([0-9]+) scalefont setfont} def\n)"
= sprintf("\\1/AxisLabelFont {\/%s findfont %d scalefont setfont} def\n/TickLabelFont {\/%s findfont %d scalefont setfont} def\n"
, AxisLabelFontType, AxisLabelFontScale, TickLabelFontType, TickLabelFontScale), str);
# second step, set defaultTitleFont and defaultFont
str := ST:-RegSubs( "(\n/defaultTitleFont) ({/Helvetica) (findfont) ([0-9]+) (scalefont setfont} def\n/defaultFont) ({/Helvetica) (findfont) ([0-9]+) (scalefont setfont} def\n)"
= sprintf("\\1 {\/%s \\3 %d \\5 {\/%s \\7 %d \\9"
, DefaultTitleFontType, DefaultTitleFontScale, DefaultFontType, DefaultFontScale), str);
# Set TickLabelFont and /AxisLabelFont (tedious tweaking, may be plot-specific)
str := StringTools:-RegSubs("(\n\\([^)]+\\)) (dup 0 stringbbox [0-9]+)"
= "\\1 AxisLabelFont \\2", str);
str := StringTools:-RegSubs("(\n\\([0-9]+\\)) (AxisLabelFont) (dup 0 stringbbox [0-9]+)"
= "\\1 TickLabelFont \\3", str);
str := StringTools:-RegSubs("(\n\\([0-9]+.[0-9]+\\)) (AxisLabelFont) (dup 0 stringbbox [0-9]+)"
= "\\1 TickLabelFont \\3", str);
str := StringTools:-RegSubs("(\n\\(\\\\[0-9]+\\)) (AxisLabelFont) (dup 0 stringbbox [0-9]+)"
= "\\1 TickLabelFont \\3", str);
str := StringTools:-RegSubs("(\n\\(\\\\[0-9]+.[0-9]+\\)) (AxisLabelFont) (dup 0 stringbbox [0-9]+)"
= "\\1 TickLabelFont \\3", str);
# Adjust thickness of the CURVES (plot-specific)
# A typical layout:
# \n medium setlinewidth
# \n[] 0 setdash defaultFont
# \n 1 0.0980392 0.188235 C
# \n medium setlinewidth
str := ST:-RegSubs("(1 [0-9]+.[0-9]+ [0-9]+.[0-9]+ C\n)(medium) (setlinewidth)"
= "\\1CurvesThickness \\3", str);
# Adjust thickness of the AXES (plot-specific)
# A typical layout:
# NP 2854 480 m 2854 500 l
# S
# medium setlinewidth
# NP 500 1234 m 2854 500 l
# S
# str := ST:-RegSubs("(\nS\n)(medium setlinewidth\n)"
# = "\\1AxesThickness setlinewidth\n", str);
str := ST:-RegSubs("(medium setlinewidth\n)(NP [0-9]+ [0-9]+ m [0-9]+ [0-9]+ l\n)"
= "AxesThickness setlinewidth\n\\2", str);
# Adjust thickness of the SYMBOL (plot-specific)
# medium setlinewidth
# 1 0.0980392 0.188235 C
# NP
# 2991 2313 m
str := ST:-RegSubs("(medium setlinewidth\n)( 1 [0-9]+.[0-9]+ [0-9]+.[0-9]+ C\n)(NP\n)([0-9]+ [0-9]+ m\)"
= "SymbolThickness setlinewidth\n\\2\\3\\4", str);
# Remove Postscript DSC error
str := ST:-RegSubs("\n%%Pages: ([0-9]+)" = "", str);
# Adjust bounding box
if margin <> 0 then
regex := "(\n%%BoundingBox: )([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)";
if not ST:-RegMatch(regex,str,'all,bb,llx,lly,urx,ury') then
error "problem matching bounding box";
end if;
bb := map(parse,[llx,lly,urx,ury]);
bb := bb + [-margin,-margin,+margin,+margin];
str := ST:-RegSubs(regex = sprintf("\\1 %d %d %d %d", op(bb)), str);
end if;
# print to file the fixed eps
FT:-Text:-WriteString(cat(dir,convert(epsfile,string),ext), str);
fclose(cat(dir,convert(epsfile,string),ext));
end proc: