# Draw a progress circle around text

I would like to draw a circle with a border containing two colors. One color should be the base color and the second color should fill up the border up to a certain percentage. For now I am only having this piece of code:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shapes}
\newcommand*\circled[1]{\tikz[baseline=(char.base)]{
\node[shape=circle,draw,inner sep=2pt, thick] (char) {#1};}}
\begin{document}
\circled{85\%}
\end{document}


Which draws a circle around the text:

What I want to achieve is this:

• Could you please make your fragment into a complete example? That would be most helpful. – cfr Sep 18 '15 at 23:35
• Thanks for the hint, I did edit it to a minimal example. – zunder Sep 18 '15 at 23:41
• Will it work if the % is added by the macro rather than specified in the argument? Only because the code is easier that way. – cfr Sep 18 '15 at 23:51
• Possible duplicate: tex.stackexchange.com/q/225949/14500 – Paul Gaborit Sep 19 '15 at 7:33
• @cfr Yes, the % can be added automatically. – zunder Sep 19 '15 at 8:22

\documentclass{standalone}
\usepackage{tikz}
\usepackage{calc}

\newcommand{\progresscircle}[1]{
\begin{tikzpicture}
\fill[black!50] (0,0) circle (\outerradius);
\fill[violet!70] (0,0) -- (0, \outerradius)
arc (90:90-3.6*#1:\outerradius) -- (0,0);
\fill[white] (0,0) circle (\innerradius);
\node (0,0) {\Huge\sffamily #1\%};
\end{tikzpicture}
}

\begin{document}
\progresscircle{85.34}

\progresscircle{41.57}
\end{document}


produces

• This won't work on a non-white background, right? For example, in a Beamer presentation. You could use \fill[black!50, even odd rule] (0,0) circle (\outerradius) (0,0) circle (\innerradius); to fill the first layer, but you'd then need a second arc to fill the second, I think, because trying to use the even odd rule there will produce artefacts, I think. (This will be viewer dependent, but presumably nice to avoid.) – cfr Sep 19 '15 at 1:59
• @cfr I still have to go with this code, as it does not cause aligning problems I had with your suggestion. – zunder Sep 19 '15 at 10:39
• You can use clip cleverly to achieve the white-out. – yo' Sep 19 '15 at 10:50

Something like this?

\documentclass{article}
\usepackage{tikz,calc}
\newlength\charwidth
\newlength\chwidth
\newcommand*\circled[1]{%
\settowidth\charwidth{#1\,\%}%
\settototalheight\chwidth{#1\,\%}%
\ifdim\chwidth>\charwidth\let\charwidth\chwidth\fi
\addtolength\charwidth{5pt}% twice inner sep plus half line width
\tikz[baseline=(char.base)]{%
\node [inner sep=2pt, circle] (char) {#1\,\%};
\draw [line width=2pt, color=basecol] (char.north) arc (90:90-#1*3.6:.5\charwidth) coordinate (a);
\draw [line width=2pt, color=othercol]  (a) arc (90-#1*3.6:-270:.5\charwidth);
}%
}
\colorlet{basecol}{purple}
\colorlet{othercol}{purple!25}
\begin{document}

\circled{87.34}

\circled{34}

\circled{20.89}

\circled{0} \circled{25} \circled{50} \circled{75} \circled{100}

\end{document}


# Key-Value Interface

Here's another approach if you want to be able to configure things to a greater extent:

\documentclass{article}
\usepackage{tikz,calc}
\makeatletter
\tikzset{
circled/.code={
\tikzset{%
/circled/.cd,
#1
}
},
circled defaults/.code={
\tikzset{%
circled={%
base=blue!50!magenta,
other=gray!25,
sep=2pt,
width=2pt,
}
}
},
/circled/.cd,
base/.store in=\circled@basecol,
other/.store in=\circled@othercol,
sep/.store in=\circled@sep,
width/.store in=\circled@width,
/tikz/circled defaults,
}
\newlength\charwidth
\newlength\chwidth
\newdimen\circled@cw
\newdimen\circled@cs
\newcommand*\circled[2][]{%
\tikzset{%
circled defaults,
circled={#1}
}%
\settowidth\charwidth{#2\,\%}%
\settototalheight\chwidth{#2\,\%}%
\ifdim\chwidth>\charwidth\let\charwidth\chwidth\fi
\circled@cw=\circled@width
\circled@cs=\circled@sep
\addtolength{\charwidth}{2\circled@cs+.5\circled@cw}% twice inner sep plus half line width
\tikz[baseline=(char.base)]{%
\node [inner sep=\circled@sep, circle] (char) {#2\,\%};
\draw [line width=\circled@width, color=\circled@basecol] (char.north) arc (90:90-#2*3.6:.5\charwidth) coordinate (a);
\draw [line width=\circled@width, color=\circled@othercol] (a) arc (90-#2*3.6:-270:.5\charwidth);
}%
}
\makeatother
\begin{document}

\circled{87.34} \circled[base=red, other=green, sep=10.2pt, width=5.5pt]{34} \circled[base=green!50!blue!50, width=3pt]{20.89}

\end{document}


# EDIT

I'm not sure what the issue with alignment is: my circles get aligned left, as I'd expect. It may be that what you really want are circles of the same size, regardless of content.

This version modifies the code above to allow this and the example shows the contrast between the dynamically-sized circles and those taking a standard size.

\documentclass{article}
\usepackage{tikz,calc}
\makeatletter
\newif\ifcircled@makesize
\tikzset{
circled/.code={
\tikzset{%
/circled/.cd,
#1
}
},
circled defaults/.code={
\tikzset{%
circled={%
base=blue!50!magenta,
other=gray!25,
sep=2pt,
width=2pt,
}
}
},
circled size/.style={%
circled={%
make size=true,
size=#1,
}
},
/circled/.cd,
base/.store in=\circled@basecol,
other/.store in=\circled@othercol,
sep/.store in=\circled@sep,
width/.store in=\circled@width,
size/.store in=\circled@size,
make size/.is if=circled@makesize,
make size=false,
size=0pt,
/tikz/circled defaults,
}
\newlength\charwidth
\newlength\chwidth
\newdimen\circled@cw
\newdimen\circled@cs
\newcommand*\circled[2][]{%
\tikzset{%
circled defaults,
circled={#1}
}%
\circled@cw=\circled@width
\ifcircled@makesize
\circled@cs=\circled@size
\setlength\charwidth{\circled@cs}%
\addtolength{\charwidth}{.5\circled@cw}% half line width
\tikz[baseline=(char.base)]{%
\node [text width=\circled@cs, align=center] (char) {#2\,\%};
\draw [line width=\circled@width, color=\circled@basecol] ([yshift=.5\charwidth]char.center) arc (90:90-#2*3.6:.5\charwidth) coordinate (a);
\draw [line width=\circled@width, color=\circled@othercol] (a) arc (90-#2*3.6:-270:.5\charwidth);
}%
\else
\settowidth\charwidth{#2\,\%}%
\settototalheight\chwidth{#2\,\%}%
\ifdim\chwidth>\charwidth\let\charwidth\chwidth\fi
\circled@cs=\circled@sep
\addtolength{\charwidth}{2\circled@cs+.5\circled@cw}% twice inner sep plus half line width
\tikz[baseline=(char.base)]{%
\node [inner sep=\circled@sep, circle] (char) {#2\,\%};
\draw [line width=\circled@width, color=\circled@basecol] (char.north) arc (90:90-#2*3.6:.5\charwidth) coordinate (a);
\draw [line width=\circled@width, color=\circled@othercol] (a) arc (90-#2*3.6:-270:.5\charwidth);
}%
\fi
}
\makeatother
\begin{document}

\noindent\circled{87.34} \circled[base=red, other=green, sep=10.2pt, width=5.5pt]{34} \circled[base=green!50!blue!50, width=3pt]{20.89}

\noindent\circled{0} \circled{25} \circled{50} \circled{75} \circled{100}

\tikzset{circled size=40pt}% switch to circles of standard size

\noindent\circled{87.34}

\noindent\circled{34}

\noindent\circled[base=green!50!blue!50]{20.89}

\noindent\circled{0} \circled{25} \circled{50} \circled{75} \circled{100}

\end{document}


If using standard sizing, the sep=<dimension> has no effect. However, the line width=<dimension> and colour options are still effective. But if you change the line width for only some circles, it will break the standard sizing, so you probably only want to alter colours on a per-circle basis in this case.

Note that it is important to set a sufficiently large size because the circles will not be adjusted if the contents is too big: the circles will remain the size you set regardless of the width and height of the contents.

• I would like to go with your solution, but there is a major shift if you draw two of the circles having different percentage, one in first, second in second line. If I have the same percentage, everything seems fine. Here is what I mean: \begin{document} \circled{99} EMPTYLINE \circled{10} \end{document} (EMPTIYLINE is just a blank line due to formating on this board.) – zunder Sep 19 '15 at 9:25
• For now, I had to go with modified version of Artem's suggestion, though I would prefer your solution. There I had almost non problems aligning the circles underneath each other. Your code seems a lot cleaner, as it does draw only the necessary lines and not simply applying circles over each other. Maybe you can fix the aligning issue somehow. – zunder Sep 19 '15 at 10:38
• @kreide How do you want them aligned? At left? And what should be aligned? The circle? Or the text? – cfr Sep 19 '15 at 12:10
• @kreide Right now, in testing, my solution aligns the circles left, so that the lines around the circles are aligned on the left. If I use \noindent, then they are aligned against the left margin, for example. This is what I'd think you'd normally want. But if you are using a Beamer presentation or something, you might want them to be centred with respect to each other. Is that what you have in mind? – cfr Sep 19 '15 at 12:19
• @kreide Please see edit. I'm assuming you want a standard size since I can't reproduce any issue with alignment as such. So I've incorporated an option for this into the code, on the assumption this is what you want. If not, please explain exactly what it is you want the code to do. – cfr Sep 19 '15 at 14:17
\documentclass[pstricks,margin=5mm]{standalone}
\degrees[100]

\def\progress#1{%
\begin{pspicture}[linewidth=5mm,dimen=m](-1,-1)(1,1)
\pscircle[linecolor=gray]{1}
\psarcn[linecolor=red](0,0){1}{25}{!25 #1 sub}
\rput(0,0){#1\%}
\end{pspicture}}

\begin{document}
\foreach \x in {0,10.5,25,50,60,75,90,100}{\progress{\x}}
\end{document}