graphing/plotting with python and interface builder
Diez B. Roggisch
deets at nospam.web.de
Sun Feb 24 07:30:54 EST 2008
Jacob Davis schrieb:
> I found SM2DGraphView, but I guess that I am too much of a newbie with
> interface builder and pyobjc to figure out how to get SM2DGraphView to
> work. Are there any good tutorials (or better yet, examples) of how to
> get SM2DGraphView to work?
>
> I don't know pyobjc well at all.
There isn't much to it. Unfortunately, there aren't many good tutorials,
but at least a few examples in the pyobjc repository.
below is my code for implementing the SM2DGraphDataSource category. It
is of course interspersed with my application-logic, but should give you
a start.
Additionally, you need to load the SM2DGraphView-framework. The code to
do so is also below.
Diez
#
# BCGraphViewController.py
# BruceControl
#
# Created by Diez Roggisch on 22.02.08.
# Copyright (c) 2008 __MyCompanyName__. All rights reserved.
#
from Foundation import *
from AppKit import *
import sys
from PyObjCTools import NibClassBuilder
import objc
MODES = "displaySpeed", "displayPosition"
kSM2DGraph_Axis_Y = 0
kSM2DGraph_Axis_X = 1
kSM2DGraph_Axis_Y_Right = 2
kSM2DGraph_Axis_Y_Left = kSM2DGraph_Axis_Y
class BCGraphViewController(NibClassBuilder.AutoBaseClass):
_displayPosition = False
_displaySpeed = False
def displayPosition(self):
return self._displayPosition
def setDisplayPosition_(self, v):
self._displayPosition= v
self.reloadData()
def displaySpeed(self):
return self._displaySpeed
def setDisplaySpeed_(self, v):
self._displaySpeed= v
self.reloadData()
def awakeFromNib(self):
self._displayed_mis = []
self._ts_min = 0.0
self._ts_max = 0.0
self.graphView.setDataSource_(self)
def setMotorInfos_(self, motor_infos):
self._motor_infos = motor_infos
# apparently, it's enough to just
# subscribe once
motor_infos[0].subscribeDisplayChanged(self)
def setConnector_(self, connector):
self._connector = connector
connector.subscribeStateListener(self)
def stateArrived_(self, n):
state = n.object()
ts = float(state.timestamp) / 1000000000.0 # nano to seconds
if self._ts_min == 0:
self._ts_min = ts
self._ts_max = ts
def reloadData(self):
if self.numberOfLinesInTwoDGraphView_(None):
self.graphView.reloadData()
self.graphView.reloadAttributes()
def displayChanged_(self, n):
motor_info = n.object()
motor_id = motor_info.motor_id
if motor_info.display() and motor_info not in self._displayed_mis:
self._displayed_mis.append(motor_info)
else:
try:
self._displayed_mis.remove(motor_info)
except ValueError:
pass
self.reloadData()
@property
def active_modes(self):
return [mode for mode in MODES if getattr(self, mode)()]
@property
def activated_views(self):
return len(self.active_modes)
@objc.signature('I@:@')
def numberOfLinesInTwoDGraphView_(self, view):
res = len(self._displayed_mis) * self.activated_views
return res
@objc.signature('@@:@I')
def twoDGraphView_dataForLineIndex_(self, view, lineIndex):
av = self.activated_views
# first, compute the mi to be used
offset = lineIndex // av
mi = self._motor_infos[offset]
mode = self.active_modes[lineIndex % av]
return mi[mode]
@objc.signature('d@:@Ii')
def twoDGraphView_maximumValueForLineIndex_forAxis_(self, view,
lineIndex, axis):
if not self.numberOfLinesInTwoDGraphView_(view):
return .0
av = self.activated_views
mode = self.active_modes[lineIndex % av]
if axis == kSM2DGraph_Axis_Y:
maxs = [mi.max[mode] for mi in self._displayed_mis]
return max(maxs)
elif axis == kSM2DGraph_Axis_X:
return float(self._ts_max)
return .0
@objc.signature('d@:@Ii')
def twoDGraphView_minimumValueForLineIndex_forAxis_(self, view,
lineIndex, axis):
if not self.numberOfLinesInTwoDGraphView_(view):
return .0
av = self.activated_views
mode = self.active_modes[lineIndex % av]
if axis == kSM2DGraph_Axis_Y:
mins = [mi.min[mode] for mi in self._displayed_mis]
return min(mins)
elif axis == kSM2DGraph_Axis_X:
return float(self._ts_min)
return .0
@objc.signature('@@:@I')
def twoDGraphView_attributesForLineIndex_(self, view, lineIndex):
try:
if not self.numberOfLinesInTwoDGraphView_(None):
return None
av = self.activated_views
# first, compute the mi to be used
offset = lineIndex // av
mi = self._motor_infos[offset]
res = {NSForegroundColorAttributeName : mi.color}
except:
print sys.exc_info()[1]
return None
return res
def crop_(self, sender):
self._ts_min = self._ts_max
for mi in self._motor_infos:
mi._set_min_max_defaults()
import objc, AppKit, Foundation, os
import logging, sys
from ctypes.util import find_library
logger = logging.getLogger('bundles')
frameworks = set(("SM2DGraphView",))
loaded = set()
loading_exceptions = []
for framework in frameworks:
logger.debug('Trying to load framework <%s>', framework)
bundle_path = find_library(framework)
bundle_path = bundle_path[:bundle_path.index('framework')] +
"framework"
logger.debug('from path <%s>', bundle_path)
try:
objc.loadBundle(framework, globals(), bundle_path=bundle_path)
loaded.add(framework)
continue
except:
loading_exceptions.append(sys.exc_info()[1])
pass
if loaded != frameworks and loading_exceptions:
logger.error("Got exceptions loading frameworks")
for e in loading_exceptions:
logger.error(e)
raise loading_exceptions[0]
del objc, AppKit, Foundation, os, bundle_path
More information about the Python-list
mailing list