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 10

Learn More

Igor XOP Toolkit

Learn More

Igor NIDAQ Tools MX

Learn More