# -------------------------------------------------------------------------
# Copyright (C) 2005-2013 Martin Strohalm
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# Complete text of GNU GPL can be found in the file LICENSE.TXT in the
# main directory of the program.
# -------------------------------------------------------------------------
# load libs
import wx
import numpy
import copy
# load modules
import mod_signal
import calculations
# MAIN PLOT OBJECTS
# -----------------
class container:
"""Container to hold plot objects."""
def __init__(self, objects):
self.objects = objects
# ----
def __additem__(self, obj):
self.objects.append(obj)
# ----
def __delitem__(self, index):
del self.objects[index]
# ----
def __setitem__(self, index, obj):
self.objects[index] = obj
# ----
def __getitem__(self, index):
return self.objects[index]
# ----
def __len__(self):
return len(self.objects)
# ----
def getBoundingBox(self, minX=None, maxX=None, absolute=False):
"""Get bounding box coverring all visible objects."""
# init values if no data in objects
rect = [numpy.array([0, 0]), numpy.array([1, 1])]
# get bouding boxes from objects
have = False
for obj in self.objects:
if obj.properties['visible']:
oRect = obj.getBoundingBox(minX, maxX, absolute)
if not oRect or not numpy.all(numpy.isfinite(oRect)):
continue
elif have and oRect:
rect[0] = numpy.minimum(rect[0], oRect[0])
rect[1] = numpy.maximum(rect[1], oRect[1])
elif oRect:
rect = oRect
have = True
# check scale
if rect[0][0] == rect[1][0]:
rect[0][0] -= 0.5
rect[1][0] += 0.5
if rect[0][1] == rect[1][1]:
rect[1][1] += 0.5
return rect
# ----
def getLegend(self):
"""Get a list of legend names."""
# get names
names = []
for obj in self.objects:
if obj.properties['visible']:
legend = obj.getLegend()
if legend and legend[0] != '':
names.append(obj.getLegend())
return names
# ----
def getPoint(self, obj, xPos, coord='screen'):
"""Get interpolated Y position for given X."""
return self.objects[obj].getPoint(xPos, coord)
# ----
def countGels(self):
"""Get number of visible gels."""
count = 0
for obj in self.objects:
if obj.properties['visible'] and obj.properties['showInGel']:
count += 1
return max(count,1)
# ----
def cropPoints(self, minX, maxX):
"""Crop points in all visible objects to selected X range."""
for obj in self.objects:
if obj.properties['visible']:
obj.cropPoints(minX, maxX)
# ----
def scaleAndShift(self, scale, shift):
"""Scale and shift all visible objects."""
for obj in self.objects:
if obj.properties['visible']:
obj.scaleAndShift(scale, shift)
# ----
def filterPoints(self, filterSize):
"""Filter points in all visible objects."""
for obj in self.objects:
if obj.properties['visible']:
obj.filterPoints(filterSize)
# ----
def draw(self, dc, printerScale, overlapLabels, reverse):
"""Draw all visible objects."""
# draw in reverse order
if reverse:
self.objects.reverse()
# draw objects
for obj in self.objects:
if obj.properties['visible']:
obj.draw(dc, printerScale)
# draw object's labels
self.drawLabels(dc, printerScale, overlapLabels)
# reverse back order
if reverse:
self.objects.reverse()
# ----
def drawLabels(self, dc, printerScale, overlapLabels):
"""Draw labels for all visible objects."""
# get labels from objects
annots = []
labels = []
for obj in self.objects:
if obj.properties['visible'] and isinstance(obj, annotations):
annots += obj.makeLabels(dc, printerScale)
elif obj.properties['visible']:
labels += obj.makeLabels(dc, printerScale)
# check labels
if not annots and not labels:
return
# sort labels
annots.sort()
annots.reverse()
labels.sort()
labels.reverse()
labels = annots + labels
# preset font by first label
font = labels[0][3]['labelFont']
colour = labels[0][3]['labelColour']
bgr = labels[0][3]['labelBgr']
bgrColour = labels[0][3]['labelBgrColour']
dc.SetFont(_scaleFont(font, printerScale['fonts']))
dc.SetTextForeground(colour)
dc.SetTextBackground(bgrColour)
if bgr:
dc.SetBackgroundMode(wx.SOLID)
# draw labels
occupied = []
for label in labels:
text = label[1]
textCoords = label[2]
properties = label[3]
# check limits
if abs(textCoords[1]) > 10000000:
continue
# check free space and draw label
if overlapLabels or self._checkFreeSpace(textCoords, occupied):
# check pen
if properties['labelFont'] != font:
font = properties['labelFont']
dc.SetFont(_scaleFont(font, printerScale['fonts']))
if properties['labelColour'] != colour:
colour = properties['labelColour']
dc.SetTextForeground(colour)
#if properties['labelBgrColour'] != bgrColour:
# bgrColour = properties['labelBgrColour']
# dc.SetTextBackground(bgrColour)
if properties['labelBgr'] != bgr:
bgr = properties['labelBgr']
if bgr:
dc.SetBackgroundMode(wx.SOLID)
else:
dc.SetBackgroundMode(wx.TRANSPARENT)
# set angle
angle = properties['labelAngle']
if angle == 90 and properties['flipped']:
angle = -90
# draw label
dc.DrawRotatedText(text, textCoords[0], textCoords[1], angle)
occupied.append(textCoords)
dc.SetBackgroundMode(wx.TRANSPARENT)
# ----
def drawGel(self, dc, gelCoords, gelHeight, printerScale):
"""Draw gel for all allowed objects."""
# draw objects
for obj in self.objects:
if obj.properties['visible'] and obj.properties['showInGel']:
obj.drawGel(dc, gelCoords, gelHeight, printerScale)
gelCoords[0] += gelHeight
# ----
def append(self, obj):
self.objects.append(obj)
# ----
def empty(self):
del self.objects[:]
# ----
def _checkFreeSpace(self, coords, occupied):
"""Check free space for label."""
curX1, curY1, curX2, curY2 = coords
# check occupied space
for occX1, occY1, occX2, occY2 in occupied:
if (curX1 < curX2) and ((occX1