Basic 2D pie charts for programmers

Couldn't find a non-dialog-driven way to make a simply pie chart, so coded this up. Comments and improvements welcome.

jeremy@bergsman.org

Function SimplePieChart(CenterX, CenterY, Radius, Values, Labels)
    //Potentially useful demonstration function for the associated pie-chart functions
    //Designed to create a pie chart at the given coordinates and size, from paired text and numeric waves containing the values and labels
    //Values assumed to represent 100% of data
    //Wedge "colors" limited to up to 5 shades of gray
    //Some effort is spent to make the shading work out nicely for arbitrary numbers of wedges
    //I have been using in the absolute coordinate system, may need some fixing to be coordinate-system agnostic

    Variable CenterX, CenterY, Radius
    Wave Values
    Wave /T Labels
   
    Variable Loop1, NumShades, Color, AltTags=.03, ArcMidPnt //AltTags value is the amount to space out a tag from the pie when it gets too crowded
    Duplicate /O Values, Degrees
    Integrate/P Values /D=Degrees
    Degrees=Degrees*360/sum(Values)
    if (numpnts(Values)<6)
        NumShades=numpnts(Values)
        AltTags=0
    else
        if (mod(numpnts(Values),5)!=1) //what's bad is if there is one left at the end, which would get the starting color
            NumShades=5
        else
            if (mod(numpnts(Values),4)!=1)
                NumShades=4
            else
                NumShades=3
            endif
        endif
    endif
    DrawWedge(CenterX, CenterY, 0, Degrees[0], Radius, 36000, 36000, 36000)
    ArcMidPnt=Degrees[0]/2
    LabelWedge("\Z08"+Labels[0], CenterX, CenterY, ArcMidPnt, Radius, AltTags*((Degrees[1]-Degrees[0])<30))
    for (Loop1=0;Loop1<numpnts(Values)-1;Loop1+=1)
        Color=36000+mod(Loop1+1,NumShades)*(24000/(NumShades-1))
        DrawWedge(CenterX, CenterY, Degrees[Loop1], Degrees[Loop1+1], Radius, Color, Color, Color)
        ArcMidPnt=(Degrees[Loop1]+Degrees[Loop1+1])/2
        LabelWedge("\Z08"+Labels[Loop1+1], CenterX, CenterY, ArcMidPnt, Radius, AltTags*mod(Loop1,2)*((Degrees[Loop1+1]-Degrees[Loop1])<30))
    endfor
End    
       

Function DrawWedge(CenterX, CenterY, StartAngle, EndAngle, Radius, Red, Green, Blue)
    //Draw a wedge with the given center position through the given angles
    //Wedges have black line border and the given color
    //Angles in degrees, Center and radius graph relative
    //End Angle must be > Start Angle
    Variable CenterX, CenterY, StartAngle, EndAngle, Radius, Red, Green, Blue
   
    if (EndAngle-StartAngle>180)
        SetDrawEnv fillfgc=(Red,Green,Blue), linethick=0
        DrawPoly CenterX, CenterY, 1, 1, {0, 0, Radius*cos((StartAngle+180)*pi/180), Radius*sin((StartAngle+180)*pi/180), Radius*cos(EndAngle*pi/180), Radius*sin(EndAngle*pi/180), 0, 0}
        SetDrawEnv fillfgc=(Red,Green,Blue)
        DrawArc /X/Y CenterX, CenterY, Radius, StartAngle, StartAngle+180
        SetDrawEnv fillfgc=(Red,Green,Blue)
        DrawArc /X/Y CenterX, CenterY, Radius, StartAngle+180, EndAngle
    else
        SetDrawEnv fillfgc=(Red,Green,Blue), linethick=0
        DrawPoly CenterX, CenterY, 1, 1, {0, 0, Radius*cos(StartAngle*pi/180), Radius*sin(StartAngle*pi/180), Radius*cos(EndAngle*pi/180), Radius*sin(EndAngle*pi/180), 0, 0}
        SetDrawEnv fillfgc=(Red,Green,Blue)
        DrawArc /X/Y CenterX, CenterY, Radius, StartAngle, EndAngle
    endif
    DrawLine CenterX, CenterY, CenterX+Radius*cos(StartAngle*pi/180), CenterY+Radius*sin(StartAngle*pi/180)
    DrawLine CenterX, CenterY, CenterX+Radius*cos(EndAngle*pi/180), CenterY+Radius*sin(EndAngle*pi/180)
End


Function LabelWedge(LabelText, CenterX, CenterY, ArcMidPnt, Radius, Offset)
    //Place a text label on a wedge.
    //Location is coded using the same kind of variables as DrawWedge for convenience
    //If Offset is non-zero, the label is placed at radius+offset, connected to the point at radius with a line
    String LabelText
    Variable CenterX, CenterY, ArcMidPnt, Radius, Offset
   
    if (Offset>0)
        DrawLine CenterX+Radius*cos(ArcMidPnt*pi/180), CenterY+Radius*sin(ArcMidPnt*pi/180), CenterX+(Offset+Radius)*cos(ArcMidPnt*pi/180), CenterY+(Offset+Radius)*sin(ArcMidPnt*pi/180)
        Radius+=Offset
    endif
    if ((ArcMidPnt>0)&&(ArcMidPnt<=90)) //This could be improved by creating 4 more compass points for angles very near 0, 90...
        TextBox /A=LT/B=1/E=2/F=0/X=(100*(CenterX+Radius*cos((ArcMidPnt)*pi/180)))/Y=(100*(CenterY+Radius*sin((ArcMidPnt)*pi/180))) LabelText
    elseif ((ArcMidPnt>90)&&(ArcMidPnt<=180))
        TextBox /A=RT/B=1/E=2/F=0/X=(100*(1-CenterX-Radius*cos((ArcMidPnt)*pi/180)))/Y=(100*(CenterY+Radius*sin((ArcMidPnt)*pi/180))) LabelText
    elseif ((ArcMidPnt>180)&&(ArcMidPnt<=270))
        TextBox /A=RB/B=1/E=2/F=0/X=(100*(1-CenterX-Radius*cos((ArcMidPnt)*pi/180)))/Y=(100*(1-CenterY-Radius*sin((ArcMidPnt)*pi/180))) LabelText
    elseif ((ArcMidPnt>270)&&(ArcMidPnt<=360))
        TextBox /A=LB/B=1/E=2/F=0/X=(100*(CenterX+Radius*cos((ArcMidPnt)*pi/180)))/Y=(100*(1-CenterY-Radius*sin((ArcMidPnt)*pi/180))) LabelText
    endif  
End

Forum

Support

Gallery

Igor Pro 9

Learn More

Igor XOP Toolkit

Learn More

Igor NIDAQ Tools MX

Learn More