Source code for tecplot.layout.frame

from contextlib import contextmanager
import logging
from six import string_types
from numbers import Number

from ..tecutil import (_tecutil, ArgList, IndexSet, StringList,
                       check_arglist_argtypes, lock, log_setattr, sv)

from .. import annotation, constant, plot, session
from ..constant import *
from ..exception import *

log = logging.getLogger(__name__)

@log_setattr
[docs]class Frame(object): """`Frame` object within a `Page`, holding onto a `Dataset` and a `Plot`. Parameters: uid (`integer <int>`, optional): This must be a *valid* unique ID number pointing internally to a Frame object or `None`. A new `Frame` is created if set to `None`. (default: `None`) page (`Page`, optional): The destination `Page` of this newly created `Frame`. If `None`, the currently active `Page` is used. (default: `None`) Warning: Though it is possible to create a `Frame` object using the constructor, it is usually sufficient to obtain a frame through `tecplot.active_frame()` or `Page.frame()`. One can also create a `Frame` using a `Page` handle with `Page.add_frame()`. The concept of the `Frame` is central to understanding the |Tecplot Engine|. The `Frame` is what connects a `Dataset` to a `Plot` handle from which one manipulates the desired image as well as accessing the attached data:: >>> import tecplot >>> frame = tecplot.active_frame() >>> frame Frame(uid=11, Page(uid=1)) >>> print(frame) Frame 001 """ page = None """The `Page` containing this Frame. This provides access to the parent `Page`:: >>> frame = tecplot.active_frame() >>> page = frame.page >>> page.name Page 001 """ def __init__(self, uid, page): log.debug('Frame(uid={uid}, page={page})'.format(uid=uid, page=repr(page))) self.page = page self.uid = uid """The internal unique ID number of this Frame.""" self._sv = [sv.FRAMELAYOUT]
[docs] def __str__(self): """Brief string representation. Returns: `string <str>`: Brief representation of this `Frame`. Example:: >>> import tecplot >>> frame = tecplot.active_frame() >>> print(frame) Frame: "Frame 001" """ return 'Frame: "{name}"'.format(name=self.name)
[docs] def __repr__(self): """Executable string representation. Returns: `string <str>`: Internal representation of this `Frame`. The string returned can be executed to generate an identical copy of this `Frame` object:: >>> import tecplot >>> frame = tecplot.active_frame() >>> frame_copy = None >>> print(repr(frame)) Frame(uid=11, page=Page(uid=1)) >>> exec('frame_copy = '+repr(frame)) >>> frame_copy Frame(uid=11, page=Page(uid=1)) >>> # frame_copy is not technically a copy. >>> # it is the same object as the original frame: >>> frame == frame_copy True """ return 'Frame(uid={uid}, page={page})'.format(uid=self.uid, page=repr(self.page))
[docs] def __eq__(self, other): """Checks for `Frame` equality in the |Tecplot Engine|. Returns: `bool`: `True` if the unique ID numbers are the same for both `Frames <Frame>`. Example:: >>> import tecplot >>> page = tecplot.active_page() >>> frame1 = page.active_frame() >>> frame2 = page.add_frame() >>> frame1 == frame2 False >>> page.active_frame() == frame2 True """ return self.uid == other.uid
def texts(self): """Get an iterator for all `Text` objects in the frame. Example usage:: Get an list of all red `Text` objects. >>> import tecplot as tp >>> all_red_text_objects = [ >>> T for T in tp.active_frame().texts() if T.color == Color.Red] """ return annotation.Annotation._Iterator(annotation.Text, self) def geometries(self): raise TecplotNotImplementedError def images(self): raise TecplotNotImplementedError @contextmanager def activated(self): """Context for temporarily activating this `Frame`. Example:: >>> import tecplot >>> page = tecplot.active_page() >>> frame1 = page.active_frame() >>> frame2 = page.add_frame() >>> print(frame2.active) True >>> with frame1.activated(): >>> print(frame1.active) True >>> print(frame2.active) True """ current_frame = Frame(_tecutil.FrameGetActiveID(), self.page) if self == current_frame: yield else: try: self.activate() yield finally: current_frame.activate() @property def name(self): """Returns or sets the name. :type: `string <str>` This is the name used when searching for `Frame` objects in `Page.frames` and `Page.frame`. It does not have to be unique, even for multiple frames in a single `Page`. Example:: >>> import tecplot >>> frame = tecplot.active_frame() >>> frame.name = '3D Data View' >>> print('this frame:', frame.name) this frame: 3D Data View """ with self.activated(): return _tecutil.FrameGetName()[1] @name.setter @lock() def name(self, name): with self.activated(): _tecutil.FrameSetName(name) @property def active(self): """Checks if this `Frame` is active. Returns: `bool`: `True` if this `Frame` is the active `Frame`. """ return self.uid == _tecutil.FrameGetActiveID() @property def current(self): return self.uid == _tecutil.FrameGetUniqueID() @lock()
[docs] def activate(self): """Causes this `Frame` to become active. Raises: `TecplotSystemError` The parent `Page` is implicitly "activated" as a side-effect of this operation:: >>> import tecplot >>> page1 = tecplot.active_page() >>> frame1 = page1.active_frame() >>> page2 = tecplot.add_page() >>> frame2 = page2.active_frame() >>> frame1.active and page1.active False >>> frame2.active and page2.active True >>> frame1.activate() >>> frame2.active or page2.active False >>> frame1.active and page1.active True """ if not self.active: if self.page is not None: self.page.activate() if not _tecutil.FrameActivateByUniqueID(self.uid): err = 'could not activate frame with uid {0}'.format(self.uid) raise TecplotSystemError(err)
@property def plot_type(self): """Returns or sets the current plot type. :type: `constant.PlotType` Raises: `TecplotSystemError` A `Frame` can have only one active plot type at any given time. The types are enumerated by `constant.PlotType`:: >>> import tecplot >>> from tecplot.constant import PlotType >>> tecplot.load_layout('mylayout.lay') >>> frame = tecplot.active_frame() >>> frame.plot_type <PlotType.Sketch: 4> >>> frame.plot_type = PlotType.Cartesian3D >>> frame.plot_type <PlotType.Cartesian3D: 1> """ return _tecutil.FrameGetPlotTypeForFrame(self.uid) @plot_type.setter @lock() def plot_type(self, plot_type): with self.activated(): res = SetValueReturnCode(_tecutil.FrameSetPlotType(plot_type.value)) if res not in [SetValueReturnCode.Ok, SetValueReturnCode.DuplicateValue]: if res is SetValueReturnCode.ContextError1: raise TecplotSystemError('no Dataset attached to Frame') raise TecplotSystemError(res)
[docs] def plot(self, plot_type=None): """Returns a `Plot` style-control object. :type: `Plot`: One of the possible `Plot` classes, depending on the ``plot_type`` specified. By default, the active plot type, obtained from `Frame.plot_type`, is used. The `Plot` object is the handle through which one can manipulate the style and visual representation of the `Dataset`. Possible return types are: `SketchPlot`, `Cartesian2DFieldPlot`, `Cartesian3DFieldPlot`, `PolarLinePlot` and `XYLinePlot`. Each of these have their own specific set of attributes and methods. Example:: >>> frame = tecplot.active_frame() >>> frame.plot_type <PlotType.Cartesian3D: 1> >>> plot3d = frame.plot() >>> plot3d.show_contour = True """ _dispatch = { PlotType.Cartesian2D: plot.Cartesian2DFieldPlot, PlotType.Cartesian3D: plot.Cartesian3DFieldPlot, PlotType.XYLine: plot.XYLinePlot, PlotType.PolarLine: plot.PolarLinePlot, PlotType.Sketch: plot.SketchPlot} return _dispatch[plot_type or self.plot_type](self)
@lock()
[docs] def move_to_bottom(self): """Moves `Frame` behind all others in `Page`. """ _tecutil.FrameMoveToBottomByUniqueID(self.uid)
@lock()
[docs] def move_to_top(self): """Moves `Frame` in front of all others in `Page`. """ _tecutil.FrameMoveToTopByUniqueID(self.uid)
@lock()
[docs] def active_zones(self, *zones): """Returns or sets the active `Zones <Zone>`. Parameters: *zones (`Zone` or `list` of `Zones <Zone>`, optional): The `Zone` objects, which must be in the `Dataset` attached to this `Frame`, that will be activated. All other `Zones <Zone>` will be deactivated. Yields: `Zones <Zone>`: This will return a generator of active `Zones <Zone>` in this `Frame`. """ with self.activated(): if zones: with IndexSet(*zones) as zoneset: _tecutil.ZoneSetActive(zoneset, AssignOp.Equals.value) else: err = 'should return generator of active zones' raise TecplotNotImplementedError(err)
@lock()
[docs] def add_text(self, text, position=None, coord_sys=None, font_family=None, bold=None, italic=None, size_units=None, size=None, color=None, angle=None, line_spacing=None, anchor=None, box_type=None, line_thickness=None, box_color=None, fill_color=None, margin=None, zone=None): """Adds a `text <annotation.Text>` to a `Frame`. Parameters: text (`string <str>`): The text to add to the `Frame`. The text string must have a non-zero length. position (`tuple` of `floats <float>` (x,y), optional): The position of the anchor in the specified coordinates. (default: (0,0)) coord_sys (`CoordSys`, optional): Coordinate system used to position the anchor of the text object. The possible values are: `CoordSys.Grid` or `CoordSys.Frame`. (default: `CoordSys.Frame`) font_family (`string <str>`, optional): The typeface family name. For consistency across various platforms, Tecplot guarantees that the following standard typeface family names are available: "Helvetica", "Times", "Courier", "Greek", "Math", and "User Defined". Other typeface family names may or may not be available depending on the TrueType fonts available. If the typeface family name or style is not available, a suitable replacement will be selected. (default: "Helvetica") bold (`boolean <bool>`, optional): Use the bold typeface of the specified font family. (default: `True`) italic (`boolean <bool>`, optional): Use the italic typeface of the specified font family. (default: `False`) size_units (`Units`, optional): Text sizing units. Possible values are: `Units.Grid`, `Units.Frame` or `Units.Point`. (default: `Units.Point`) size (`float`, optional): Text height in the specified units. (default: 14) color (`Color`, optional): Color of the text (default: `Color.Black`) angle (`float`, optional): Angle of the text baseline in degrees from -360 to 360. (default: 0) line_spacing (`float`, optional): Line spacing in units of line size. Can take values from 0 to 50. (default: 1) anchor (`TextAnchor`, optional): Anchor position with respect to the text box. Possible values are: `TextAnchor.Left`, `TextAnchor.Center`, `TextAnchor.Right`, `TextAnchor.MidLeft`, `TextAnchor.MidCenter`, `TextAnchor.MidRight`, `TextAnchor.HeadLeft`, `TextAnchor.HeadCenter`, `TextAnchor.HeadRight`, `TextAnchor.OnSide` (default: `TextAnchor.Left`) box_type (`constant.TextBox`, optional): Type of text box can be one of: `TextBox.None_`, `TextBox.Filled` or `TextBox.Hollow`. (default: `TextBox.None_`) line_thickness (`float`, optional): Text box boarder line thickness may be a value in the range from 0.0001 to 100. (default: 0.1) box_color (`Color`, optional): Text box border line color. See `Color` for possible values. (default: `Color.Black`) fill_color (`Color`, optional): Text box fill color. See `Color` for possible values. (default: `White`) margin (`float`, optional): Margin between the text and text box. May be in the range from 0 to 2000. (default: 20) zone (`Zone`, optional): `Zone` or `XYLinemap` to which the text will be attached. (default: None) Returns: `annotation.Text`: The resulting `text box <annotation.Text>` object. Example:: >>> import tecplot >>> from tecplot.constant import Color >>> frame = tecplot.active_frame() >>> frame.add_text('Hello, World!', position=(35, 50), ... bold=True, italic=False, text_color=Color.Blue) """ with self.activated(): with ArgList() as arglist: if __debug__: check_arglist_argtypes( 'frame.add_text', ([tuple], [position], ['position']), ([CoordSys], [coord_sys], ['coord_sys']), (string_types, [font_family, text], ['font_family', 'text']), ([bool], [bold, italic], ['bold', 'italic']), ([Units], [size_units], ['size_units']), ([Number], [size, angle, line_thickness, margin, line_spacing], ['size', 'angle', 'line_thickness', 'margin', 'line_spacing']), ([Color], [color, box_color, fill_color], ['color', 'text_color', 'fill_color']), ([TextAnchor], [anchor], ['anchor']), ([TextBox], [box_type], ['box_type']), ) if zone is not None: arglist[sv.ATTACHTOZONE] = True arglist[sv.ZONE] = zone.index + 1 # Note that TecUtil calls SV_TEXTCOLOR the color of the text, # and SV_COLOR as the text *box* color. These names correspond # to the 'color' and 'box_color' parameters. arglist.update( (sv.TEXT, text), (sv.XPOS, position[0] if position is not None else None, float), (sv.YPOS, position[1] if position is not None else None, float), (sv.POSITIONCOORDSYS, coord_sys), (sv.ISBOLD, bold), (sv.ISITALIC, italic), (sv.SIZEUNITS, size_units), (sv.HEIGHT, size, float), (sv.ANGLE, angle, float), (sv.LINETHICKNESS, line_thickness, float), (sv.MARGIN, margin, float), (sv.ANCHOR, anchor), (sv.LINESPACING, line_spacing, float), (sv.COLOR, box_color), (sv.TEXTCOLOR, color), (sv.FILLCOLOR, fill_color), (sv.BOXTYPE, box_type)) return annotation.Text(_tecutil.TextCreateX(arglist), self)
@lock()
[docs] def create_dataset(self, name, var_names=None, reset_style=False): """Create an empty `Dataset`. This will create a new `Dataset` and replace the existing one, destroying all data associated with it. Parameters: name (`string <str>`): Title of the new `Dataset`. This does not have to be unique. var_names (`list` of `strings <str>`, optional): `Variable` names. This only sets the names and not the data type or location. See `add_variable`. (default: `None`) reset_style (`boolean <bool>`): Reset style of the active `Frame` before loading the `Dataset`. (default: `False`) Returns: `Dataset`: The newly created `Dataset`. Raises: `TecplotSystemError` """ with self.activated(): if var_names is not None: var_names = StringList(*var_names) try: if not _tecutil.DataSetCreate(name, var_names, reset_style): raise TecplotSystemError() finally: if var_names is not None: var_names.dealloc() return self.dataset
def _get_style(self, rettype, *svargs): svargs = self._sv + list(svargs) return session.get_style(rettype, *svargs, uniqueid=self.uid) def _set_style(self, value, *svargs): svargs = self._sv + list(svargs) session.set_style(value, *svargs, uniqueid=self.uid) @property def background_color(self): """Color of the background. :type: `Color` """ return self._get_style(constant.Color, sv.BACKGROUNDCOLOR) @background_color.setter def background_color(self, value): self._set_style(constant.Color(value), sv.BACKGROUNDCOLOR) @property def border_thickness(self): """The border thickness in units of `Frame.size_pos_units`. :type: `float` """ return self._get_style(float, sv.BORDERTHICKNESS) @border_thickness.setter def border_thickness(self, value): self._set_style(float(value), sv.BORDERTHICKNESS) @property def height(self): """The height in units of `Frame.size_pos_units`. :type: `float` """ return self._get_style(float, sv.HEIGHT) @height.setter def height(self, value): self._set_style(float(value), sv.HEIGHT) @property def show_border(self): """Show or hide the `Frame`'s border. :type: `bool` """ return self._get_style(bool, sv.SHOWBORDER) @show_border.setter def show_border(self, value): self._set_style(bool(value), sv.SHOWBORDER) @property def show_header(self): """Show or hide the `Frame`'s header in the border. :type: `bool` """ return self._get_style(bool, sv.SHOWHEADER) @show_header.setter def show_header(self, value): self._set_style(bool(value), sv.SHOWHEADER) @property def header_background_color(self): """The header's background color. :type: `Color` """ return self._get_style(constant.Color, sv.HEADERCOLOR) @header_background_color.setter def header_background_color(self, value): self._set_style(constant.Color(value), sv.HEADERCOLOR) @property def size_pos_units(self): """The units used for size properties. :type: `FrameSizePosUnits` Possible values: `Paper`, `Workspace <FrameSizePosUnits.Workspace>`. """ return self._get_style(constant.FrameSizePosUnits, sv.FRAMESIZEPOSUNITS) @size_pos_units.setter def size_pos_units(self, value): self._set_style(constant.FrameSizePosUnits(value), sv.FRAMESIZEPOSUNITS) @property def transparent(self): """Use transparency within this `Frame`. :type: `bool` """ return self._get_style(bool, sv.ISTRANSPARENT) @transparent.setter def transparent(self, value): self._set_style(bool(value), sv.ISTRANSPARENT) @property def width(self): """The width in units of `Frame.size_pos_units`. :type: `float` """ return self._get_style(float, sv.WIDTH) @width.setter def width(self, value): self._set_style(float(value), sv.WIDTH)