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