mirror of
https://github.com/rdkit/rdkit.git
synced 2026-06-04 21:54:27 +08:00
122 lines
3.6 KiB
Python
Executable File
122 lines
3.6 KiB
Python
Executable File
# $Id$
|
|
#
|
|
# Copyright (C)2003-2006 Rational Discovery LLC
|
|
#
|
|
# @@ All Rights Reserved @@
|
|
#
|
|
""" functionality for drawing hierarchical catalogs on sping
|
|
canvases
|
|
|
|
"""
|
|
from sping import pid as piddle
|
|
|
|
class VisOpts(object):
|
|
circRad = 10
|
|
minCircRad = 4
|
|
maxCircRad = 16
|
|
circColor = piddle.Color(0.6,0.6,0.9)
|
|
terminalEmptyColor = piddle.Color(.8,.8,.2)
|
|
terminalOnColor = piddle.Color(0.8,0.8,0.8)
|
|
terminalOffColor = piddle.Color(0.2,0.2,0.2)
|
|
outlineColor = piddle.transparent
|
|
lineColor = piddle.Color(0,0,0)
|
|
lineWidth = 1
|
|
horizOffset = 5
|
|
vertOffset = 75
|
|
topMargin = 20
|
|
labelFont = piddle.Font(face='helvetica',size=10)
|
|
highlightColor = piddle.Color(1.,1.,.4)
|
|
highlightWidth = 2
|
|
|
|
visOpts = VisOpts()
|
|
|
|
def GetMinCanvasSize(adjList,levelList):
|
|
maxAcross = -1
|
|
for k in levelList.keys():
|
|
nHere = len(levelList[k])
|
|
maxAcross = max(maxAcross,nHere)
|
|
nLevs = len(levelList.keys())
|
|
minSize = ( maxAcross*(visOpts.minCircRad*2+visOpts.horizOffset),
|
|
visOpts.topMargin + nLevs * visOpts.vertOffset )
|
|
return minSize
|
|
|
|
def DrawHierarchy(adjList,levelList,canvas,entryColors=None,
|
|
bitIds=None,minLevel=-1,maxLevel=1e8):
|
|
"""
|
|
|
|
Arguments:
|
|
|
|
- adjList: adjacency list representation of the hierarchy to be drawn
|
|
|
|
- levelList: dictionary mapping level -> list of ids
|
|
|
|
"""
|
|
if bitIds is None:
|
|
bitIds = []
|
|
if entryColors is None:
|
|
entryColors = {}
|
|
|
|
levelLengths = levelList.keys()
|
|
levelLengths.sort()
|
|
minLevel = max(minLevel,levelLengths[0])
|
|
maxLevel = min(maxLevel,levelLengths[-1])
|
|
|
|
dims = canvas.size
|
|
drawLocs = {}
|
|
# start at the bottom of the hierarchy and work up:
|
|
for levelLen in range(maxLevel,minLevel-1,-1):
|
|
nLevelsDown = levelLen-minLevel
|
|
pos = [0,visOpts.vertOffset*nLevelsDown+visOpts.topMargin]
|
|
|
|
ids = levelList.get(levelLen,[])
|
|
|
|
# FIX: we'll eventually want to figure out some kind of sorting here:
|
|
nHere = len(ids)
|
|
canvas.defaultFont=visOpts.labelFont
|
|
if nHere:
|
|
# figure the size of each node at this level:
|
|
spacePerNode = float(dims[0]) / nHere
|
|
spacePerNode -= visOpts.horizOffset
|
|
nodeRad = max(spacePerNode/2,visOpts.minCircRad)
|
|
nodeRad = min(nodeRad,visOpts.maxCircRad)
|
|
spacePerNode = nodeRad*2+visOpts.horizOffset
|
|
# start in the midde of the canvas:
|
|
pos[0] = dims[0]/2.
|
|
# maybe we need to offset a little:
|
|
if nHere%2:
|
|
pos[0] -= spacePerNode/2
|
|
|
|
# move to the left by half the number of nodes:
|
|
pos[0] -= (nHere // 2 - .5) * spacePerNode
|
|
|
|
# Find the locations and draw connectors:
|
|
for id in ids:
|
|
if not bitIds or id in bitIds:
|
|
# first do lines down to the next level:
|
|
if levelLen != maxLevel:
|
|
for neighbor in adjList[id]:
|
|
if drawLocs.has_key(neighbor):
|
|
p2 = drawLocs[neighbor][0]
|
|
canvas.drawLine(pos[0],pos[1],p2[0],p2[1],
|
|
visOpts.lineColor,visOpts.lineWidth)
|
|
drawLocs[id] = tuple(pos),nodeRad
|
|
pos[0] += spacePerNode
|
|
|
|
for id in drawLocs.keys():
|
|
pos,nodeRad = drawLocs[id]
|
|
x1,y1 = pos[0]-nodeRad,pos[1]-nodeRad
|
|
x2,y2 = pos[0]+nodeRad,pos[1]+nodeRad
|
|
drawColor = entryColors.get(id,visOpts.circColor)
|
|
canvas.drawEllipse(x1,y1,x2,y2,visOpts.outlineColor,
|
|
0,drawColor)
|
|
label = str(id)
|
|
#txtLoc = ( pos[0]-canvas.stringWidth(label)/2,
|
|
# pos[1]+canvas.fontHeight()/4 )
|
|
txtLoc = ( pos[0]+canvas.fontHeight()/4,
|
|
pos[1]+canvas.stringWidth(label)/2)
|
|
canvas.drawString(label,txtLoc[0],txtLoc[1],angle=90)
|
|
|
|
return drawLocs
|
|
|
|
|