Home
Manual
Packages
Global Index
Keywords
Quick Reference
|
/*
STYLE.I
Get and set graphics styles from within the Yorick interpreter.
$Id$
*/
/* Copyright (c) 1996. The Regents of the University of California.
All rights reserved. */
func get_style (&landscape, &systems, &legends, &clegends)
/* DOCUMENT get_style, landscape, systems, legends, clegends
get the detailed style of the current drawing. The arguments
are all outputs:
landscape: 1 if drawing is landscape orientation, 0 if portrait
system: an array of GfakeSystem struct instances, one per
coordinate system in this drawing (ordinarily just one).
legends: a GeLegendBox structure instance describing the layout
of the plot legends
clegends: a GeLegendBox structure instance describing the layout
of the contour legends
See the help for the GeLegendBox and GpTextAttribs structs for
the details of the legends and clegends arguments. Basically,
you can adjust the location of the legends on the page, the
font and height of the characters used to render legends, and
whether the legends are split into two columns.
The coordinate systems are the systems accessible via the
plsys command. The index of the system in the system array is
the index you use to switch to it in the plsys command. Simple
styles have only one coordinate system, and you should carefully
consider whether you should design a graphic style with multiple
coordinate systems -- most likely, you can do a better job by
combining several separate Yorick pictures with some sort of
page layout program, rather than trying to do this work within
Yorick itself.
See the help for the GfakeSystem struct for complete details of
what you can adjust. The most interesting features you can
control are the location and aspect ratio of the viewport, and
the details of the axis ticks and labels. The gridxy function
provides a simpler interface for fiddling with ticks and labels
if that is all you need. The system.viewport member is the
[xmin,xmax,ymin,ymax] of the rectangle on the page where your
plots will appear, expressed in NDC coordinates (0.0013 NDC units
equals one point, and there are 72.27 points per inch, and 2.54
cm per inch; the NDC origin is always at the lower left hand
corner of the paper, with x increasing leftward and y increasing
upward). If you change the size of the viewport, you will also
need to change the parameters of the tick-generating model; like
other problems in typography and page layout, this is harder
than you might think.
SEE ALSO: set_style, read_style, write_style
*/
{
landscape= [0n];
n= raw_style(0, landscape, &[], &[]);
if (!n) error, "no current drawing";
systems= array(GfakeSystem, n);
legends= array(GeLegendBox, 2);
raw_style, 0, landscape, &systems, &legends;
landscape= landscape(1);
clegends= legends(2);
legends= legends(1);
}
func set_style (landscape, systems, legends, clegends)
/* DOCUMENT set_style, landscape, systems, legends, clegends
set the detailed style of the current drawing. The arguments
are all inputs, having the same meanings as for get_style (which
see). All arguments are required, so you may need to call
get_style as a starting point, if you only want to make a few
changes. See the Y_SITE/g/work.gs and the other .gs files for
examples of reasonable values to choose.
Calling set_style destroys anything that was plotted in the
window, like the style= keyword of the window command.
SEE ALSO: get_style, read_style, write_style
*/
{
if (structof(systems)!=GfakeSystem || structof(legends)!=GeLegendBox ||
structof(clegends)!=GeLegendBox || numberof(legends)!=1 ||
numberof(clegends)!=1 || numberof(landscape)!=1 ||
structof(landscape+0)!=long)
error, "illegal input data types or sizes";
landscape= [int(landscape(1))];
raw_style, numberof(systems), landscape, &systems, &[legends,clegends];
}
/* ------------------------------------------------------------------------ */
func write_style (file, landscape, systems, legends, clegends)
/* DOCUMENT write_style, file, landscape, systems, legends, clegends
write a Gist style sheet (.gs file), using the data structures
as described in the get_style function. The FILE can be a
filename or a text file stream.
SEE ALSO: get_style, set_style, read_style
*/
{
if (structof(file)==string) file= create(file);
write,file,format="# %s\n",
"Gist style sheet made by Yorick write_style function";
write,file,format="# Created: %s\n", timestamp();
write,file,format="# (%ld coordinate systems)\n\n", numberof(systems);
write,file,format="landscape= %d\n\n", (landscape!=0);
for (i=1 ; i<=numberof(systems) ; ++i) {
sys= systems(i);
if (i==1) {
default= sys;
which= "default";
} else {
which= "system";
}
legend= sys.legend;
if (!strlen(legend)) legend= "0";
else legend= "\""+legend+"\"";
write,file,format="%s= { legend= %s", which, (i>1? legend : "0");
final= " }";
vp= sys.viewport;
if (i==1 || anyof(vp!=default.viewport)) {
final= "}";
write,file,format=",\n viewport= { %f, %f, %f, %f }",
vp(1),vp(2),vp(3),vp(4);
}
ticks= sys.ticks;
if (i==1 || ticks!=default.ticks) {
final= "}";
write,file,format=",\n%s\n", " ticks= {"
axes= [ticks.horiz, ticks.vert];
daxes= [default.ticks.horiz, default.ticks.vert];
prefix= "\n ";
for (j=1 ; j<=2 ; ++j) {
axis= axes(j);
daxis= daxes(j);
if (i==1 || axis!=daxis) {
write,file,format="%s%s= {\n", prefix, (j==1? "horiz" : "vert");
nitems= 0;
prefix= " "; suffix= "";
if (i==1 || axis.nMajor!=daxis.nMajor) {
write,file,format="%snMajor= %f", prefix, axis.nMajor;
prefix= ", "; suffix= " ";
++nitems;
}
if (i==1 || axis.nMinor!=daxis.nMinor) {
write,file,format="%snMinor= %f", prefix, axis.nMinor;
prefix= ", "; suffix= " ";
++nitems;
}
if (i==1 || axis.logAdjMajor!=daxis.logAdjMajor) {
write,file,format="%slogAdjMajor= %f", prefix, axis.logAdjMajor;
prefix= ", "; suffix= " ";
if ((++nitems)==3) {
nitems= 0;
prefix= ",\n ";
}
}
if (i==1 || axis.logAdjMinor!=daxis.logAdjMinor) {
write,file,format="%slogAdjMinor= %f", prefix, axis.logAdjMinor;
prefix= ", "; suffix= " ";
if ((++nitems)==3) {
nitems= 0;
prefix= ",\n ";
}
}
if (i==1 || axis.nDigits!=daxis.nDigits) {
write,file,format="%snDigits= %d", prefix, axis.nDigits;
prefix= ", "; suffix= " ";
if ((++nitems)==3) {
nitems= 0;
prefix= ",\n ";
}
}
if (i==1 || axis.gridLevel!=daxis.gridLevel) {
write,file,format="%sgridLevel= %d", prefix, axis.gridLevel;
prefix= ", "; suffix= " ";
if ((++nitems)==3) {
nitems= 0;
prefix= ",\n ";
}
}
if (i==1 || axis.flags!=daxis.flags) {
write,file,format="%sflags= 0x%03x", prefix, axis.flags;
prefix= ", "; suffix= " ";
if ((++nitems)==3) {
nitems= 0;
prefix= ",\n ";
}
}
if (i==1 || axis.tickOff!=daxis.tickOff) {
write,file,format="%stickOff= %f", prefix, axis.tickOff;
prefix= ", "; suffix= " ";
if ((++nitems)==3) {
nitems= 0;
prefix= ",\n ";
}
}
if (i==1 || axis.labelOff!=daxis.labelOff) {
write,file,format="%slabelOff= %f", prefix, axis.labelOff;
prefix= ", "; suffix= " ";
if ((++nitems)==3) {
nitems= 0;
prefix= ",\n ";
}
}
if (i==1 || anyof(axis.tickLen!=daxis.tickLen)) {
if (prefix!=" ") prefix= ",\n ";
_style_wvect, file, prefix, "tickLen", axis.tickLen;
prefix= ",\n "; suffix= ""; nitems= 0;
}
if (i==1 || axis.tickStyle!=daxis.tickStyle) {
if (prefix!=" ") prefix= ",\n ";
_style_wline, file, prefix, "tickStyle", axis.tickStyle;
prefix= ",\n "; suffix= ""; nitems= 0;
}
if (i==1 || axis.gridStyle!=daxis.gridStyle) {
if (prefix!=" ") prefix= ",\n ";
_style_wline, file, prefix, "gridStyle", axis.gridStyle;
prefix= ",\n "; suffix= ""; nitems= 0;
}
if (i==1 || axis.textStyle!=daxis.textStyle) {
if (prefix!=" ") prefix= ",\n ";
_style_wtext, file, prefix, "textStyle", axis.textStyle;
prefix= ",\n "; suffix= ""; nitems= 0;
}
if (i==1 || axis.xOver!=daxis.xOver) {
write,file,format="%sxOver= %f", prefix, axis.xOver;
prefix= ", "; suffix= " ";
if ((++nitems)==3) prefix= ",\n ";
}
if (i==1 || axis.yOver!=daxis.yOver) {
write,file,format="%syOver= %f", prefix, axis.yOver;
suffix= " ";
}
write,file,format="%s}", suffix;
prefix= ",\n\n "; suffix= "";
}
}
if (i==1 || ticks.frame!=default.ticks.frame) {
write,file,format="%sframe= %d", prefix, ticks.frame;
prefix= ",\n "; suffix= " ";
}
if (i==1 || ticks.frameStyle!=default.ticks.frameStyle) {
_style_wline, file, prefix, "frameStyle", ticks.frameStyle;
suffix= "";
}
write,file,format="%s}", suffix;
}
write,file,format="%s\n", final;
if (i==1) {
write,file,format="\nsystem= { legend= %s }\n", legend;
}
}
legs= [legends,clegends];
for (i=1 ; i<=2 ; ++i) {
leg= legs(i);
if (leg.nlines) {
write,file,format="\n%slegends= {\n", (i==1? "" : "c");
write,file,format=" x= %f, y= %f, dx= %f, dy= %f",
leg.x, leg.y, leg.dx, leg.dy;
_style_wtext, file, ",\n ", "textStyle", leg.textStyle;
write,file,format=",\n nchars= %d, nlines= %d, nwrap= %d }\n",
leg.nchars, leg.nlines, leg.nwrap;
} else {
write,file,format="\n%slegends= { nlines= 0 }\n", (i==1? "" : "c");
}
}
return file;
}
func _style_wvect (file, prefix, member, value)
{
write,file,format="%s%s= {", prefix, member;
prefix= " ";
for (i=1 ; i<=numberof(value) ; ++i) {
write,file,format="%s%f", prefix, value(i);
prefix= ", ";
}
write,file,format="%s}", " ";
}
func _style_wline (file, prefix, member, style)
{
write,file,format="%s%s= { color= %d, type= %d, width= %f }",
prefix, member, style.color, style.type, style.width;
}
func _style_wtext (file, prefix, member, style)
{
write,file,format="%s%s= { color= %d, font= 0x%02x, height= %f",
prefix, member, style.color, style.font, style.height;
if (strpart(prefix,1:1)!=",") {
if (strpart(prefix,1:1)!="\n") prefix= ",\n"+prefix;
else prefix= ","+prefix;
}
write,file,format="%s orient= %d, alignH= %d, alignV= %d, opaque= %d }",
prefix, style.orient, style.alignH, style.alignV, style.opaque;
}
func read_style (file, &landscape, &systems, &legends, &clegends)
/* DOCUMENT read_style, file, landscape, systems, legends, clegends
read a Gist style sheet (.gs file), and return the data
structures as described in the get_style function. The FILE
can be a filename or a text file stream.
SEE ALSO: get_style, set_style, write_style
*/
{
if (structof(file)==string) {
f= open(file, "r", 1);
if (!f) {
/* maybe the file is in one of the standard locations */
f= open("~/gist/"+file, "r", 1);
if (!f) {
f= open("~/Gist/"+file, "r", 1);
if (!f) {
f= open(Y_SITE+"g/"+file, "r", 1);
if (!f) error, "missing style file: "+file;
}
}
}
} else {
f= file;
}
/* set up default values (same as work.gs) */
landscape= 0n;
default_line= GpLineAttribs(color= 254, type= 1, width= 1.0);
default_text= GpTextAttribs(
color= 254, font= 0x08, height= 0.0182,
orient= 0, alignH= 0, alignV= 0, opaque= 0);
default_ltxt= GpTextAttribs(
color= 254, font= 0x00, height= 0.0156,
orient= 0, alignH= 1, alignV= 1, opaque= 0);
default= GfakeSystem(viewport=[0.19, 0.60, 0.44, 0.85],
ticks= GaTickStyle(
horiz= GaAxisStyle(
nMajor=7.5, nMinor=50.0, logAdjMajor=1.2, logAdjMinor=1.2,
nDigits=3, gridLevel=1, flags=0x033, tickOff=0.0007, labelOff=0.0182,
tickLen= [0.0143, 0.0091, 0.0052, 0.0026, 0.0013],
tickStyle= default_line,
gridStyle= GpLineAttribs(color= 254, type= 3, width= 1.0),
textStyle= default_text,
xOver= 0.395, yOver= 0.370),
vert= GaAxisStyle(
nMajor=7.5, nMinor=50.0, logAdjMajor=1.2, logAdjMinor=1.2,
nDigits=3, gridLevel=1, flags=0x033, tickOff=0.0007, labelOff=0.0182,
tickLen= [0.0143, 0.0091, 0.0052, 0.0026, 0.0013],
tickStyle= default_line,
gridStyle= GpLineAttribs(color= 254, type= 3, width= 1.0),
textStyle= default_text,
xOver= 0.150, yOver= 0.370),
frame= 0,
frameStyle= GpLineAttribs(color= 254, type= 1, width= 1.0)));
default_legb= GeLegendBox(
x= 0.04698, y= 0.360, dx= 0.3758, dy= 0.0,
textStyle= default_ltxt, nchars= 36, nlines= 20, nwrap= 2);
default_clegb= GeLegendBox(
x= 0.6182, y= 0.8643, dx= 0.0, dy= 0.0,
textStyle= default_ltxt, nchars= 14, nlines= 28, nwrap= 1);
legends= default_legb;
clegends= default_clegb;
/* parse the file */
systems= [];
type= [];
line= "";
for (;;) {
s= _style_token(f, line, type);
if (!line) break;
if (type!=3) _style_goof, f, line, s;
if (s=="landscape") {
landscape= _style_token(f, line, type);
if (type!=2 || structof(landscape)!=long)
_style_goof, f, line, "landscape= ????";
landscape= (landscape!=0);
} else if (s=="default") {
default= _style_system(f, line, default);
} else if (s=="system") {
grow, systems, [_style_system(f, line, default)];
} else if (s=="legends") {
legends= _style_legends(f, line, default_legb);
} else if (s=="clegends") {
clegends= _style_legends(f, line, default_clegb);
} else {
_style_goof, f, line, s;
}
}
if (is_void(systems)) systems= [default];
}
func _style_system (f, &line, default)
{
system= default;
type= [];
s= _style_token(f, line, type);
if (s!="{") _style_goof, f, line, s;
for (;;) {
s= _style_token(f, line, type);
if (type!=3) _style_goof, f, line, s;
if (s=="legend") {
s= _style_token(f, line, type);
if (type!=1) {
if (type==2 && s==0) s= string(0);
else _style_goof, f, line, s;
}
system.legend= s;
} else if (s=="viewport") {
system.viewport= _style_vector(f,line);
} else if (s=="ticks") {
system.ticks= _style_ticks(f,line,system.ticks);
} else {
_style_goof, f, line, s;
}
s= _style_token(f, line, type);
if (s=="}") break;
if (s!=",") _style_goof, f, line, s;
}
return system;
}
func _style_legends (f, &line, default)
{
legend= default;
type= [];
s= _style_token(f, line, type);
if (s!="{") _style_goof, f, line, s;
for (;;) {
s= _style_token(f, line, type);
if (type!=3) _style_goof, f, line, s;
if (s=="textStyle")
get_member(legend,s)= _style_text(f,line,default.textStyle);
else
get_member(legend,s)= _style_token(f,line,type);
s= _style_token(f, line, type);
if (s=="}") break;
if (s!=",") _style_goof, f, line, s;
}
return legend;
}
func _style_ticks (f, &line, default)
{
ticks= default;
type= [];
s= _style_token(f, line, type);
if (s!="{") _style_goof, f, line, s;
for (;;) {
s= _style_token(f, line, type);
if (type!=3) _style_goof, f, line, s;
if (s=="horiz" || s=="vert") {
get_member(ticks,s)= _style_axis(f,line,get_member(ticks,s));
} else if (s=="frame") {
ticks.frame= _style_token(f,line,type);
} else if (s=="frameStyle") {
ticks.frameStyle= _style_line(f,line,ticks.frameStyle);
} else {
_style_goof, f, line, s;
}
s= _style_token(f, line, type);
if (s=="}") break;
if (s!=",") _style_goof, f, line, s;
}
return ticks;
}
func _style_axis (f, &line, default)
{
axis= default;
type= [];
s= _style_token(f, line, type);
if (s!="{") _style_goof, f, line, s;
for (;;) {
s= _style_token(f, line, type);
if (type!=3) _style_goof, f, line, s;
if (s=="tickLen") {
value= _style_vector(f, line);
axis.tickLen(1:numberof(value))= value;
} else if (s=="tickStyle" || s=="gridStyle") {
get_member(axis,s)= _style_line(f,line,get_member(axis,s));
} else if (s=="textStyle") {
axis.textStyle= _style_text(f,line,axis.textStyle);
} else {
get_member(axis,s)= _style_token(f,line,type);
}
s= _style_token(f, line, type);
if (s=="}") break;
if (s!=",") _style_goof, f, line, s;
}
return axis;
}
func _style_vector (f, &line)
{
vector= type= [];
s= _style_token(f, line, type);
if (s!="{") _style_goof, f, line, s;
for (;;) {
s= _style_token(f, line, type);
if (type!=2) _style_goof, f, line, s;
grow, vector, [double(s)];
s= _style_token(f, line, type);
if (s=="}") break;
if (s!=",") _style_goof, f, line, s;
}
return vector;
}
func _style_text (f, &line, default)
{
junk= [0.0];
text= default;
type= [];
s= _style_token(f, line, type);
if (s!="{") _style_goof, f, line, s;
for (;;) {
s= _style_token(f, line, type);
if (type!=3) _style_goof, f, line, s;
if (text=="path") text= "orient";
if (noneof(text==["expand","spacing","upX","upY"]))
get_member(text,s)= _style_token(f,line,type);
else
junk(1)= _style_token(f,line,type);
s= _style_token(f, line, type);
if (s=="}") break;
if (s!=",") _style_goof, f, line, s;
}
if (text.color < 0) text.color += 256;
return text;
}
func _style_line (f, &line, default)
{
style= default;
type= [];
s= _style_token(f, line, type);
if (s!="{") _style_goof, f, line, s;
for (;;) {
s= _style_token(f, line, type);
if (type!=3) _style_goof, f, line, s;
get_member(style,s)= _style_token(f,line,type);
s= _style_token(f, line, type);
if (s=="}") break;
if (s!=",") _style_goof, f, line, s;
}
if (style.color < 0) style.color += 256;
return style;
}
/* retrieve next token from file, updating current line
-- set line to "" initially
-- on output, type= 0 is delimiter, 1 is quoted, 2 is number, 3 keyword
*/
func _style_token (f, &line, &type, norecurse)
{
s= "";
for (;;) {
/* give up if no more lines in file */
if (!line) return line;
/* remove leading whitespace */
sread, line, s, format="%[ \t]";
line= strpart(line, 1+strlen(s):0);
/* stop if line has more chars, and is not a comment */
if (strlen(line)) {
s= strpart(line,1:1);
if (s!="#") break;
}
/* otherwise get the next line and try again */
line= rdline(f);
}
/* look at first character to see if this is a delimiter */
cs= (*pointer(s))(1);
if (anyof(['{','}',',','=']==cs)) {
/* token is one of the four valid delimiters */
line= strpart(line,2:0);
type= 0;
return string(&[cs,'\0']);
} else if (cs=='"') {
/* token is a quoted string */
s= strtok(line, "\"");
type= 1;
line= s(2);
return s(1);
}
/* token must be either a number or a keyword */
s= strtok(line, " \t{},=")(1);
line= strpart(line, strlen(s)+1:0);
if ((cs>='0' && cs<='9') || cs=='.' || cs=='-') {
/* token is a number */
if (strmatch(s,".") || strmatch(s,"e",1)) {
value= 0.0;
if (!sread(s,value)) _style_goof, f, line, s;
} else {
value= 0;
if (!sread(s,value,format="%i")) _style_goof, f, line, s;
}
type= 2;
return value;
} else {
/* if next token is =, this token is a keyword */
if (!norecurse) next= _style_token(f, line, type, 1);
if (type==0 && next=="=") {
type= 3;
return s;
} else {
_style_goof, f, line, s;
}
}
}
func _style_goof (f, line, s)
{
write, "graphics style file format error at or just before:";
write, print(f)(2);
error, "unrecognized token: "+pr1(s);
}
/* ------------------------------------------------------------------------ */
/* The following structure definitions must match those in
Gist/gist.h and Gist/draw.h */
/* Note: NDC units 0.0013 equals one point equals 1/72.27 inch */
one_point= 0.0013;
one_inch= 72.27*one_point;
struct GpLineAttribs {
long color; /* 255=bg 254=fg 253=b 252=w ...=rgb ...=cmy */
int type; /* line types: 0=none 1=solid 2=- 3=. 4=-. 5=-.. */
double width; /* 1.0 is normal width of a line (1/2 point) */
}
struct GpTextAttribs {
long color; /* 255=bg 254=fg 253=b 252=w ...=rgb ...=cmy */
int font; /* text font
fonts: 0=courier 4=times 8=helvetica 12=symbol
16=newcentury
or with 1 for bold, 2 for italic */
double height; /* character height in NDC, default 0.0156 (12pt)
UNLIKE GKS, GIST font sizes are always specified
in NDC. This drastically simplifies coding for
devices like X windows, which must load a font
at each size. It also conforms better with
a Mac-like user interface in which font size
in points is selected by the user. */
int orient; /* text orientation: 0=right 1=left 2=up 3=down */
int alignH, alignV; /* text alignments:
alignH: 0=normal 1=left 2=center 3=right
alignV: 0=normal 1=top 2=cap 3=half 4=base 5=bot */
int opaque;
}
struct GaAxisStyle {
double nMajor, nMinor, logAdjMajor, logAdjMinor;
int nDigits, gridLevel;
int flags; /* 0x001 ticks on lower edge
0x002 ticks on upper edge
0x004 ticks in center
0x008 inward ticks
0x010 outward ticks
0x020 labels on lower edge
0x040 labels on upper edge
0x080 full grid lines
0x100 origin grid line */
double tickOff, labelOff; /* offsets in NDC from the edge of the
viewport to the ticks or labels */
double tickLen(5); /* tick lengths in NDC */
GpLineAttribs tickStyle, gridStyle;
GpTextAttribs textStyle; /* alignment ignored, set correctly */
double xOver, yOver; /* position for overflow label */
}
struct GaTickStyle {
GaAxisStyle horiz, vert;
int frame;
GpLineAttribs frameStyle;
}
struct GeLegendBox {
double x, y; /* NDC location of this legend box */
double dx, dy; /* if non-zero, offset to 2nd column */
GpTextAttribs textStyle; /* font, size, etc. of these legends */
int nchars, nlines; /* max number of characters per line, lines */
int nwrap; /* max number of lines to wrap long legends */
}
struct GfakeSystem {
double viewport(4); /* [xmin,xmax,ymin,ymax] in NDC coordinates */
GaTickStyle ticks; /* tick style for this coordinate system */
string legend; /* e.g.- "System 0" or "System 1" */
}
/* ------------------------------------------------------------------------ */
|