1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
|
# Copyright (c) 1996, 1997, The Regents of the University of California.
# All rights reserved. See Legal.htm for full text and disclaimer.
GraphicsError = "GraphicsError"
from types import *
from graftypes import *
import os
try:
graphics = os.environ["PYGRAPH"]
except KeyError:
print "env variable PYGRAPH is not set, so assuming Gist graphics."
print "...this can be overruled by the 'graphics' keyword argument"
print " to Graph2d or Graph3d."
graphics = "Gist"
if graphics [0:3] == "Nar" :
import NarPlotter
Graphics = NarPlotter
elif graphics == "Gist" :
import GistPlotter
Graphics = GistPlotter
else :
raise GraphicsError , \
graphics + " is an unknown graphics package. Check PYGRAPH " + \
"environment variable."
# The following is so I know about arrays:
from Numeric import *
from scipy_base.fastumath import *
from shapetest import *
class Graph :
"""
g = Graph ( <keyword arguments> ) abstracts all the information
that is common to 2d, 3d, and 4d graphs, and will be inherited from
by all of those types. It is never intended to be instantiated
except via a derived class. The keyword arguments are:
plotter = <Plotter object> or a sequence of <Plotter object>s
if you have a plotter object or a sequence of them that
you want the graph to use when plotting itself. I
recommend against this; a graph can create its own
plotter if you don't give it one.
filename = <string> or a sequence of <string>s if you want to
connect to a Plotter with the named file(s). (The default
is " ".) Only one of the keywords 'plotter' or 'filename'
is allowed, and both are optional.
NOTE: the possibility of a sequence of file names or
plotters allows one to display Plotter on one's
own machine as well as one or more remote machines.
In Gist, the filename argument is the same as the
display argument (below).
hardcopy = <string> Allows the user to specify a hardcopy file
for this Plotter object. If string ends in ".ps", this will
be postscript; it ".cgm", then it will be cgm.
This is valid only for Gist; ignored for Narcisse.
display = <string> or a sequence of <string>s if you want to
display on the named hosts. The form of <string> is
the usual "hostname:server.screen". The purpose of
this argument is to allow you to continue without
exiting python if you have to open a Gist window
without the DISPLAY environment variable having been
set, or if you want to open Gist windows on more
than one host.
graphics = <string> or a sequence of <string>s if you want to
specify which graphics the particular plotter connects to.
Currently the values allowed are "Nar" and "Gist".
This argument is meaningless if you supply a list
of plotters. If it is a scalar and you supply a list
of filenames, all plotters opened will be that type.
If it is a vector, then it must match the list of
filenames in size and correspond to the filename.
titles = <value> where <value> is a string or a sequence
of up to four strings, giving the titles in the
order bottom, top, left, right.
title_colors = <value> where value is an integer or string
or a sequence of up to four integers or strings giving
the colors of the titles.
axis_labels = <value> where <value> is a string or
for a 2d Graph: a sequence of up to three strings
representing the labels of the x axis, the y axis,
and the right y axis. for a 3d Graph: a sequence of
up to four strings representing the labels of the
x axis, the y axis, the z axis, and the right y axis.
axis_limits = <value> where <value> is a pair [xmin, xmax] or
for a 2d Graph: a sequence of up to three pairs,
where the second would be the y limits and the third
the right y limits. for a 3d or 4d graph:
a sequence of up to five pairs, where the second
would be the y limits, the third the z limits,
the fourth the c limits, and the fifth the right
y limits. axis_limits = "defaults" will let the
graphics calculate the limits.
x_axis_limits, y_axis_limits, yr_axis_limits, z_axis_limits,
and c_axis_limits are used to change the limits on
individual axes. They may be set to a pair or to
"defaults".
axis_scales = "linlin", "linlog", "loglin", or "loglog" for
2d graphs with no separate right y axis; if there is
a separate yr axis, and it is not to default to
linear, then the scales must be expressed as a
sequence of three values "log" or "lin" with the
third one (for yr) "log". For 3d and 4d plots,
one or a sequence of up to five values "log" or "lin"
which are specified in the order x, y, z, c, and yr.
x_axis_scale, y_axis_scale, yr_axis_scale, z_axis_scale,
and c_axis_scale are used to change the scale on
individual axes. They may be set to "log" or "lin".
text = <value> where value is one or a sequence of strings
representing texts to be placed on the plot.
text_color = <value> where <value> is one or a sequence
of color numbers or names giving colors for the
texts.
text_size = <value> where <value> is one or a sequence of
integers giving (roughly) the number of characters
in a line on the graph.
text_pos = <value> where <value> is a pair or a sequence or
reals between 0. and 1.0 giving the relative
position of the lower left corner of a text
in the graphics window.
xyequal = 0/1 If 1, the axis limits will be adjusted so that
both axes are to the same scale.
sync = 0 or 1 (1 to synchronize before plotting)
defaults to 1, otherwise plots may get garbled.
color_bar = 0 or 1 (1 enables plotting of a color bar on
any graphs for which it is meaningful (colored contour
plots, filled contour plots, cell arrays, filled
meshes and polygons).
color_bar_pos (ignored unless a color bar is actually plotted)
is a 2d array [ [xmin, ymin], [xmax, ymax]] specifying
where (in window coordinates) the diagonally opposite
corners of the color bar are to be placed.
"""
def _initialize_generics ( self , keywords ) :
"""_initialize_generics ( keywords ) is called from __init__ to
set all those things which are generic to a graph: sync,
axis_labels, axis_scales, axis_limits, etc., and
titles, title_colors, text, text_color, text_size, and text_pos.
Gives no default if keyword is not present, so can be called
by change.
Formerly, this routine used to do color conversions between
graphics versions. Not any more; that has been relegated to
the Plotter level.
This routine has also been changed to delete generic items from
the keywords so that other items can be changed as well. It was
not intuitive why calling 'change' would not change any item
you pleased.
"""
if keywords.has_key ("sync") :
self._sync = keywords ["sync"]
del keywords ["sync"]
if keywords.has_key ("titles") :
self._titles = keywords ["titles"]
if type (self._titles) == StringType :
self._titles = [self._titles]
del keywords ["titles"]
if keywords.has_key ("title_colors") :
self._title_colors = keywords ["title_colors"]
del keywords ["title_colors"]
if keywords.has_key ("text") :
self._text = keywords ["text"]
del keywords ["text"]
if keywords.has_key ("text_color") :
self._text_color = keywords ["text_color"]
del keywords ["text_color"]
if keywords.has_key ("text_size") :
self._text_size = keywords ["text_size"]
del keywords ["text_size"]
if keywords.has_key ("text_pos") :
self._text_pos = keywords ["text_pos"]
del keywords ["text_pos"]
if keywords.has_key ("tosys") :
self._tosys = keywords ["tosys"]
del keywords ["tosys"]
self._init_axis_labels (keywords)
# handle keywords which take care of all axes
if keywords.has_key ("axis_scales") :
axs = keywords ["axis_scales"]
if is_scalar (axs) and self._scale_dict_2d.has_key (axs) :
axs = self._scale_dict_2d [axs]
if is_scalar (axs) :
self._axis_scales [0] = axs
else :
for i in range (len (axs)) :
self._axis_scales [i] = axs [i]
del keywords ["axis_scales"]
if keywords.has_key ("axis_limits") :
axl = keywords ["axis_limits"]
if axl == "defaults" :
for i in range (self._no_of_axes) :
self._axis_limits [i] = [0., 0.]
elif is_scalar (axl) :
raise self._AxisSpecError , \
"Axis limits must be a point."
elif type (axl) == ListType or type (axl) == ArrayType :
if type (axl [0]) != ListType and type (axl [0]) != ArrayType :
self._axis_limits [0] = axl
else :
for i in range (len (axl)) :
self._axis_limits [i] = axl [i]
else :
raise self._AxisSpecError , \
"Axis limits are incomprehensible."
del keywords ["axis_limits"]
if keywords.has_key ("color_bar") :
self._color_bar = keywords ["color_bar"]
else :
self._color_bar = 0
if keywords.has_key ("color_bar_pos") :
self._color_bar_pos = keywords ["color_bar_pos"]
else :
self._color_bar_pos = None
# handle individual axis keywords
for i in range (self._no_of_axes) :
if keywords.has_key (self._scale_keywords [i]) :
self._axis_scales [i] = keywords [self._scale_keywords [i]]
del keywords [self._scale_keywords [i]]
if keywords.has_key (self._limits_keywords [i]) :
self._axis_limits [i] = keywords [self._limits_keywords [i]]
del keywords [self._limits_keywords [i]]
if keywords.has_key ( "xyequal") :
self._xyequal = keywords ["xyequal"]
del keywords ["xyequal"]
# common to all Graph classes
_GraphInitError = "GraphInitError"
_GraphSpecError = "GraphSpecError"
_AxisSpecError = "AxisSpecError"
_scale_dict_2d = { "linlin" : ["lin", "lin"] ,
"linlog" : ["lin", "log"] ,
"loglin" : ["log", "lin"] ,
"loglog" : ["log", "log"] }
def __init__ ( self , * kwds , ** keywords ) :
global Graphics
self._send_coordinates = 1
if len (kwds) == 1 :
keywords = kwds[0]
if not hasattr (self, "_filename_list") :
self._filename_list = []
if not hasattr (self, "_plotter_list") :
self._plotter_list = []
if ( keywords.has_key ("filename") or keywords.has_key ("display")) \
and keywords.has_key ("plotter") :
raise self._GraphInitError , \
"Only one keyword, 'filename (display)' or 'plotter' allowed."
if keywords.has_key ("hardcopy") :
self._hardcopy = keywords ["hardcopy"]
else :
self._hardcopy = ""
self._graphics_list = [Graphics]
if keywords.has_key ("filename") or keywords.has_key ("display") :
if keywords.has_key ("graphics") :
if keywords ["graphics"] == "" or keywords ["graphics"] is None :
self._graphics_list = [Graphics]
elif keywords ["graphics"] == "Nar" or \
keywords ["graphics"] == "Narcisse" :
self._graphics_list = [NarPlotter]
elif keywords ["graphics"] == "Gist" :
self._graphics_list = [GistPlotter]
else :
self._graphics_list = keywords ["graphics"]
if is_scalar (self._graphics_list) :
self._graphics_list = [self._graphics_list]
for i in range (len (self._graphics_list)) :
if self._graphics_list [i] == "Gist" :
self._graphics_list [i] = GistPlotter
elif self._graphics_list [i] == "Nar" or \
self._graphics_list [i] == "Narcisse" :
self._graphics_list [i] = NarPlotter
else :
raise self._GraphInitError , "Illegal graphics option: " + \
self._graphics_list [i]
if keywords.has_key ("filename") :
fn = keywords ["filename"]
else :
fn = keywords ["display"]
if is_scalar (fn) and not fn in self._filename_list :
self._filename_list.append (fn)
self._plotter_list.append (-1)
else :
for i in range (len (fn)) :
if not fn [i] in self._filename_list :
self._filename_list.append (fn [i])
self._plotter_list.append (-1)
self._plotters_started = 0
elif keywords.has_key ("plotter") :
pl = keywords ["plotter"]
if is_scalar (pl) and not pl in self._plotter_list :
self._plotter_list.append (pl)
self._filename_list.append (" ")
else :
for i in range (len (pl)) :
if not pl [i] in self._plotter_list :
self._plotter_list.append (pl [i])
self._filename_list.append (" ")
self._plotters_started = 1
self._titles = [" ", " ", " ", " "]
self._title_colors = "fg"
self._text = " "
self._text_color = 1
self._text_size = 0
self._text_pos = [0.,0.]
self._tosys = 0
self._sync = 1
self._xyequal = 0
self._initialize_generics ( keywords )
def _init_axis_labels ( self , keywords ) :
"""_init_axis_labels ( kw ) sets the axis labels if keywords are present.
This routine can be called by quick_plot in a dervied class.
"""
if keywords.has_key ("axis_labels") :
axl = keywords ["axis_labels"]
if is_scalar (axl) :
self._axis_labels [0] = axl
else :
for i in range (len (axl)) :
self._axis_labels [i] = axl [i]
del keywords ["axis_labels"]
if keywords.has_key ("gnomon") :
self._gnomon = keywords ["gnomon"]
del keywords ["gnomon"]
else :
self._gnomon = 0
for i in range (self._no_of_axes) :
if keywords.has_key (self._label_keywords [i]) :
self._axis_labels [i] = keywords [self._label_keywords [i]]
del keywords [self._label_keywords [i]]
def add_file ( self, fn ) :
"""add_file ( "filename" ) allows the user to add a plotter
contacted via "filename" to the list of plotters being used
by this object.
"""
self._filename_list.append (fn)
self._plotter_list.append (-1)
self._plotters_started = 0
add_display = add_file
def delete_file ( self, fn ) :
"""delete_file ( "filename" ) allows the user to delete a plotter
contacted via "filename" from the list of plotters being used
by this object.
"""
if fn in self._filename_list :
self._filename_list.remove (fn)
return
delete_display = delete_file
def add_plotter ( self, pl ) :
"""add_plotter ( pl ) allows the user to add the specified
plotter to the list of plotters being used by this object.
"""
self._plotter_list.append (pl)
self._filename_list.append (" ")
def delete_plotter ( self, pl ) :
"""delete_plotter ( pl ) allows the user to delete the specified
plotter from the list of plotters being used by this object.
"""
if pl in self._plotter_list :
self._plotter_list.remove (pl)
return
def change ( self, * kwds , ** keywords ) :
"""change ( <keyword arguments> ) allows some of the graph's
generic characteristics to be changed.
Actually it allows any keyword values to be changed. It should
be used with care, as it does no error checking.
"""
if len (kwds) == 1 :
keywords = kwds[0]
self._initialize_generics ( keywords )
for k in keywords.keys ( ) :
setattr ( self, "_" + k , keywords [k] )
def _init_plotter ( self ) :
""" _init_plotter (): initializer routine which will start up
plotter(s) if necessary. This routine is called from the plot
routine of a derived class.
"""
try :
Graphics = self._graphics_list [0]
except :
raise self._GraphInitError, "No graphics specified??"
if self.type () == Graph2dType :
dpi = 100
else :
dpi = 75
if len (self._plotter_list) == 0 :
# If user has not specified a plotter, create a default
self._filename_list.append (" ")
self._plotter_list.append (Graphics.Plotter (" " ,
style = self._style, dpi = dpi, hcp = self._hardcopy))
else :
for i in range (len (self._plotter_list)) :
# start up plotters for any unspecified ones.
if self._plotter_list [i] == -1 :
if len (self._plotter_list) > 1 :
Graphics = self._graphics_list [i]
self._plotter_list [i] = Graphics.Plotter (
self._filename_list [i] , style = self._style, dpi = dpi,
hcp = self._hardcopy)
self._plotters_started = 1
|