Christopher Barker wrote:
I'm about to post some new code for that

Enclosed is my new version of PieChart. I'm still going to do a bit of rearranging, then add it to the floatcanvas package in a new sub-module: SpecialObjects. I'd love to have whatever testing I could get before that.

One of these days, I'd really like to re-factor and put all the DrawObject classes in their own module, rather than in the FloatCanvas module anyway...

I've set it up with a list of default colors -- I'd love a better list if someone has one -- maybe 10 or so distinct colors.

A couple of the charts will print a message if you click on them.

Please give it try!

-Chris




--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R            (206) 526-6959   voice
7600 Sand Point Way NE   (206) 526-6329   fax
Seattle, WA  98115       (206) 526-6317   main reception

[EMAIL PROTECTED]
import wx

## import a local version of FloatCanvas

import sys
sys.path.append("../../")
from floatcanvas import NavCanvas, FloatCanvas
from floatcanvas.Utilities import BBox

from ArcObject import ArcPoint

import numpy as N

XYObjectMixin = FloatCanvas.XYObjectMixin
LineOnlyMixin = FloatCanvas.LineOnlyMixin
DrawObject = FloatCanvas.DrawObject
class PieChart(XYObjectMixin, LineOnlyMixin, DrawObject):
    """
    This is DrawObject for a pie chart
    
    You can pass in a bunch of values, and it will draw a pie chart for
    you, and it will make the chart, scaling the size of each "slice" to
    match your values.
    
    The parameters are:
    
     XY : The (x,y) coords of the center of the chart
     Diameter : The diamter of the chart in worls coords, unless you set
                "Scaled" to False, in which case it's in pixel coords.
     Values : sequence of values you want to make the chart of.
     FillColors=None : sequence of colors you want the slices. If
                       None, it will choose (no guarantee youll like them!)
     FillStyles=None : Fill style you want ("Solid", "Hash", etc)
     LineColor = None : Color of lines separating the slices
     LineStyle = "Solid" : style of lines separating the slices
     LineWidth    = 1 : With of lines separating the slices
     Scaled = True : Do you want the pie to scale when zooming? or stay the same size in pixels?
     InForeground = False: Should it be on the foreground?             
    

    """
    
    
    ##fixme: this should be a longer and better designed set.
    DefaultColorList = ["Red", "Green", "Blue", "Purple", "Yellow", "Cyan"]

    def __init__(self,
                 XY,
                 Diameter,
                 Values,
                 FillColors=None,
                 FillStyles=None,
                 LineColor = None,
                 LineStyle = "Solid",
                 LineWidth    = 1,
                 Scaled = True,
                 InForeground = False):               
        DrawObject.__init__(self, InForeground)

        self.XY = N.asarray(XY, N.float).reshape( (2,) )
        self.Diameter = Diameter
        self.Values = N.asarray(Values, dtype=N.float).reshape((-1,1))
        if FillColors is None:
            FillColors = self.DefaultColorList[:len(Values)]
        if FillStyles is None:
            FillStyles = ['Solid'] * len(FillColors)
        self.FillColors = FillColors
        self.FillStyles = FillStyles
        self.LineColor = LineColor
        self.LineStyle = LineStyle

        self.Scaled = Scaled
        self.InForeground = InForeground
        
        self.SetPen(LineColor, LineStyle, LineWidth)
        self.SetBrushes()
        self.CalculatePoints()

    def SetFillColors(self, FillColors):
        self.FillColors = FillColors
        self.SetBrushes()

    def SetFillStyles(self, FillStyles):
        self.FillStyles = FillStyles
        self.SetBrushed()

    def SetValues(self, Values):
        Values = N.asarray(Values, dtype=N.float).reshape((-1,1))
        self.Values = Values
        self.CalculatePoints()

    def CalculatePoints(self):
        # add the zero point to start
        Values = N.vstack( ( (0,), self.Values) )
        Diameter = self.Diameter

        Fractions = Values/Values.sum()
        Angles = 2*N.pi * Fractions
        Angles = N.cumsum(Angles, axis=0)
        Angles[-1,0] = 0 # this should be a full circle, and we want to avoid rounding error.
        CirclePoints = N.hstack( (N.cos(Angles)*Diameter, N.sin(Angles)*Diameter) )
        if self.Scaled:
            CirclePoints += self.XY
        else:
            CirclePoints = CirclePoints * (1, -1) #(in pixel coords, y is down)
        self.Points = CirclePoints
        
        self.CalcBoundingBox()
        

    def SetBrushes(self):
        self.Brushes = []
        for FillColor, FillStyle in zip(self.FillColors, self.FillStyles):
            if FillColor is None or FillStyle is None:
                self.Brush = wx.TRANSPARENT_BRUSH
            else:
                self.Brushes.append(self.BrushList.setdefault( (FillColor, FillStyle),
                                                               wx.Brush( FillColor, self.FillStyleList[FillStyle] )
                                                              )
                                    )
    def CalcBoundingBox(self):
        if self.Scaled:
            self.BoundingBox = BBox.asBBox( ((self.XY-self.Diameter),(self.XY+self.Diameter)) )
        else:
            self.BoundingBox = BBox.asBBox((self.XY, self.XY))
        if self._Canvas:
            self._Canvas.BoundingBoxDirty = True

    def _Draw(self, dc , WorldToPixel, ScaleWorldToPixel, HTdc=None):
        CenterXY = WorldToPixel(self.XY)
        if self.Scaled:
            CirclePoints = WorldToPixel(self.Points)
        else:
            CirclePoints = self.Points + CenterXY
        dc.SetPen(self.Pen)
        for i, brush in enumerate(self.Brushes):
            dc.SetBrush( brush )
            dc.DrawArcPoint(CirclePoints[i], CirclePoints[i+1], CenterXY)
        if HTdc and self.HitAble:
            if self.Scaled:
                radius = (ScaleWorldToPixel(self.Diameter)/2)[0]# just the x-coord
            else:
                radius = self.Diameter/2
            HTdc.SetPen(self.HitPen)
            HTdc.SetBrush(self.HitBrush)
            HTdc.DrawCirclePoint(CenterXY, radius)
#!/usr/bin/env python


import wx

## import the installed version
#from wx.lib.floatcanvas import NavCanvas, FloatCanvas

## import a local version
import sys
sys.path.append("../")
from floatcanvas import NavCanvas, FloatCanvas

import numpy as N

class DrawFrame(wx.Frame):

    """
    A frame used for the FloatCanvas Demo

    """

    def __init__(self, *args, **kwargs):
        wx.Frame.__init__(self, *args, **kwargs)

        self.CreateStatusBar()

        # Add the Canvas
        Canvas = NavCanvas.NavCanvas(self,-1,
                                     size = (500,500),
                                     Debug = 0,
                                     BackgroundColor = "DARK SLATE BLUE",
                                     ).Canvas
      
        self.Canvas = Canvas
        from PieChart import PieChart

        Values = (10,10,10)
        Colors = ('Red', 'Blue', 'Green')
        Pie1 = PieChart(N.array((0, 0)), 10, Values, Colors, Scaled=False)
        Canvas.AddObject(Pie1)
        
        Values = (10, 5, 5)
        Pie2 = PieChart(N.array((40, 0)), 10, Values, Colors)
        Canvas.AddObject(Pie2)
          
        # test default colors
        Values = (10, 15, 12, 24, 6, 12)
        Pie3 = PieChart(N.array((20, 20)), 10, Values, LineColor="Black")
        Canvas.AddObject(Pie3)
        
        # missng slice!
        Values = (10, 15, 12, 24)
        Colors = ('Red', 'Blue', 'Green', None)
        Pie4 = PieChart(N.array((0, -15)), 10, Values, Colors, LineColor="Black")
        Canvas.AddObject(Pie4)
        

        # Test the styles
        Values = (10, 12, 14)
        Styles = ("Solid", "CrossDiagHatch","CrossHatch")
        Colors = ('Red', 'Blue', 'Green')
        Pie4 = PieChart(N.array((20, -20)), 10, Values, Colors, Styles)
        Canvas.AddObject(Pie2)

        Pie1.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.Pie1Hit)
        Pie2.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.Pie2Hit)

        FloatCanvas.EVT_MOTION(self.Canvas, self.OnMove ) 

        self.Show()
        Canvas.ZoomToBB()

    def Pie1Hit(self, obj):
        print "Pie1 hit!"

    def Pie2Hit(self, obj):
        print "Pie2 hit!"

    def OnMove(self, event):
        """
        Updates the status bar with the world coordinates
        """
        self.SetStatusText("%.2g, %.2g"%tuple(event.Coords))


app = wx.App(False)
F = DrawFrame(None, title="FloatCanvas Demo App", size=(700,700) )
app.MainLoop()
_______________________________________________
FloatCanvas mailing list
[email protected]
http://mail.mithis.com/cgi-bin/mailman/listinfo/floatcanvas

Reply via email to