graphing/plotting with python and interface builder

Diez B. Roggisch deets at nospam.web.de
Sun Feb 24 13:30:54 CET 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