00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 from PyQt4.QtCore import *
00019 from PyQt4.QtGui import *
00020
00021 def flatten(x):
00022 """flatten(sequence) -> list
00023
00024 Returns a single, flat list which contains all elements retrieved
00025 from the sequence and all recursively contained sub-sequences
00026 (iterables).
00027
00028 Examples:
00029 >>> [1, 2, [3,4], (5,6)]
00030 [1, 2, [3, 4], (5, 6)]
00031 >>> flatten([[[1,2,3], (42,None)], [4,5], [6], 7, MyVector(8,9,10)])
00032 [1, 2, 3, 42, None, 4, 5, 6, 7, 8, 9, 10]"""
00033 result = []
00034 for el in x:
00035
00036 if hasattr(el, "__iter__") and not isinstance(el, basestring):
00037 result.extend(flatten(el))
00038 else:
00039 result.append(el)
00040 return result
00041
00042
00043
00044 class ColorManager:
00045 colorList = [ QColor('#%02x%02x%02x' % (25+((r+10)%11)*23,5+((g+1)%11)*20,25+((b+4)%11)*23) ) for r in range(11) for g in range(11) for b in range(11) ]
00046
00047
00048 def __init__(self, count):
00049 self.list = ColorManager.pickColors(count)
00050
00051
00052 def pen(self, i):
00053 return QPen( self.edgeColor(i) )
00054
00055
00056 def brush(self, i):
00057 g = QLinearGradient(0, 0, 200, 200)
00058 g.setColorAt( 0.0, self.color(i) )
00059 color = self.color(i)
00060 edge = QColor()
00061 edge.setRed( min( color.red()+45, 255 ) )
00062 edge.setGreen( min( color.green()+45, 255 ) )
00063 edge.setBlue( min( color.blue()+45, 255 ) )
00064 g.setColorAt( 1.0, edge )
00065 return QBrush( g )
00066
00067
00068 def color(self, i):
00069 i = i % len(self.list)
00070 return QColor( self.list[i] )
00071
00072
00073
00074 def edgeColor( self, i ):
00075 i = i % len(self.list)
00076 color = self.color(i)
00077 edge = QColor()
00078 edge.setRed( max( color.red()-45, 0 ) )
00079 edge.setGreen( max( color.green()-45, 0 ) )
00080 edge.setBlue( max( color.blue()-45, 0 ) )
00081 return edge
00082
00083
00084
00085 @staticmethod
00086 def pickColors(n):
00087 if n:
00088 return ColorManager.colorList[0:-1:len(ColorManager.colorList)/(n+1)]
00089 else:
00090 return []
00091
00092
00093 class LegendItem(QGraphicsItemGroup):
00094
00095 def __init__(self, parent):
00096 QGraphicsPathItem.__init__(self, parent)
00097 self._labels = []
00098 self._rects = []
00099 self._texts = []
00100 self._background = QGraphicsPathItem(self)
00101 self._background.setBrush( QBrush( QColor( 230, 230, 230, 200 ) ) )
00102 self._background.setPen( QPen( QColor( 64, 64, 64, 200 ) ) )
00103 self.setZValue( 2 )
00104 self._chartWidth = 0
00105
00106 def setChartWidth(self, width):
00107 self._width = width
00108
00109 def chartWidth(self):
00110 if self._width:
00111 return self._width
00112 else:
00113 return self.scene().width()
00114
00115 def setLabels(self, labels):
00116 self._labels = labels
00117 self.updateLabels()
00118
00119 def updateLabels(self):
00120 self.clear()
00121 if len(self._labels) == 0:
00122 return
00123 font = QFont()
00124 metrics = QFontMetrics( font )
00125 y = 0
00126 manager = ColorManager( len(self._labels) )
00127 maxWidth = 0
00128 maxHeight = 0
00129 for i in range(len(self._labels)):
00130 label = self._labels[i]
00131
00132 text = QGraphicsSimpleTextItem( self )
00133 text.setPos( 35, y )
00134 text.setText( label )
00135 text.setZValue( 2 )
00136 self._texts.append( text )
00137 maxWidth = max( maxWidth, 35 + text.boundingRect().right() )
00138
00139 rect = QGraphicsRectItem(self)
00140
00141
00142 rect.setRect( 0, y + 2, 30, metrics.boundingRect('N').height() - 4 )
00143 rect.setBrush( manager.brush(i) )
00144 rect.setPen( manager.pen(i) )
00145 rect.setZValue( 2 )
00146 self._rects.append( rect )
00147
00148 self.addToGroup( text )
00149 self.addToGroup( rect )
00150
00151 y += metrics.lineSpacing()
00152
00153
00154 maxHeight = max( text.boundingRect().bottom(), rect.boundingRect().bottom() )
00155
00156
00157 path = QPainterPath()
00158 rect = QRectF( -5, -5, maxWidth + 10, maxHeight + 10 )
00159 path.addRoundedRect( rect, 5.0, 5.0 )
00160 self._background.setPath( path )
00161
00162 def clear(self):
00163 for rect in self._rects:
00164 self.removeFromGroup( rect )
00165 rect.setParentItem( None )
00166 del rect
00167 self._rects = []
00168 for text in self._texts:
00169 self.removeFromGroup( text )
00170 text.setParentItem( None )
00171 del text
00172 self._texts = []
00173
00174 def place(self):
00175 if not self.scene():
00176 return
00177 rect = self.mapToScene( self.boundingRect() ).boundingRect()
00178 rect.setX( 0 )
00179 rect.setWidth( self.scene().width() )
00180
00181
00182
00183
00184 self.setVisible( False )
00185 items = self.scene().items( rect )
00186 self.setVisible( True )
00187
00188
00189
00190 if self.parentItem() in items:
00191 items.remove( self.parentItem() )
00192
00193 def sortByX(x, y):
00194 i = x.mapToScene( x.boundingRect() ).boundingRect().x()
00195 j = y.mapToScene( y.boundingRect() ).boundingRect().x()
00196 if i > j:
00197 return 1
00198 elif i < j:
00199 return -1
00200 else:
00201 return 0
00202
00203 items.sort( sortByX )
00204 maxWidth = 0
00205 maxWidthPosition = 0
00206 for x in range(len(items)+1):
00207 if x > 0:
00208 i = items[x-1].mapToScene( items[x-1].boundingRect() ).boundingRect().right()
00209 else:
00210 i = 0
00211 if x < len(items):
00212 j = items[x].mapToScene( items[x].boundingRect() ).boundingRect().x()
00213 else:
00214 j = self.chartWidth()
00215 width = j - i
00216 if maxWidth < width:
00217 maxWidth = width
00218 maxWidthPosition = i
00219 self.setPos( maxWidthPosition + maxWidth / 2 - self.boundingRect().width() / 2, self.pos().y() )
00220
00221
00222
00223
00224 class AbstractGraphicsChartItem(QGraphicsItemGroup):
00225
00226 def __init__(self, parent=None):
00227 QGraphicsItemGroup.__init__(self, parent)
00228 self._values = []
00229 self._labels = []
00230 self._categories = []
00231 self._items = []
00232 self._showLegend = True
00233 self._legend = LegendItem( self )
00234 self._legend.setPos( 300, 5 )
00235 self._size = QSize( 200, 200 )
00236
00237 def setSize( self, size ):
00238 self._size = size
00239 self._legend.setChartWidth( self._size.width() )
00240 self.updateChart()
00241
00242 def height(self):
00243 return self._size.height()
00244
00245 def width(self):
00246 return self._size.width()
00247
00248 def setValues( self, values ):
00249 self.clear()
00250 self._values = values
00251 self.updateChart()
00252
00253 def setLabels( self, labels ):
00254 self._labels = labels
00255 self._legend.setLabels( labels )
00256 self.updateChart()
00257
00258
00259 def updateChart(self):
00260 pass
00261
00262 def setShowLegend( self, show ):
00263 self._showLegend = show
00264
00265 def clear(self):
00266 for item in self._items:
00267 self.removeFromGroup( item )
00268 del item
00269 self._items = []
00270