32

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:

enter image description here

What I want to achieve is this:

progress

5
  • Could you please make your fragment into a complete example? That would be most helpful.
    – cfr
    Commented Sep 18, 2015 at 23:35
  • Thanks for the hint, I did edit it to a minimal example.
    – zunder
    Commented Sep 18, 2015 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
    Commented Sep 18, 2015 at 23:51
  • Possible duplicate: tex.stackexchange.com/q/225949/14500 Commented Sep 19, 2015 at 7:33
  • @cfr Yes, the % can be added automatically.
    – zunder
    Commented Sep 19, 2015 at 8:22

4 Answers 4

31
\documentclass{standalone}
\usepackage{tikz}
\usepackage{calc}
\newlength{\outerradius}
\newlength{\innerradius}
\setlength{\outerradius}{2cm}
\setlength{\innerradius}{1.5cm}

\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

progress circle

3
  • 1
    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
    Commented Sep 19, 2015 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
    Commented Sep 19, 2015 at 10:39
  • 1
    You can use clip cleverly to achieve the white-out.
    – yo'
    Commented Sep 19, 2015 at 10:50
33

Something like this?

progress circle

\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}

progress circles

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}

percentages with key-value configuration

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}

dynamically-sized and standard-size circles

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.

5
  • 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
    Commented Sep 19, 2015 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
    Commented Sep 19, 2015 at 10:38
  • @kreide How do you want them aligned? At left? And what should be aligned? The circle? Or the text?
    – cfr
    Commented Sep 19, 2015 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
    Commented Sep 19, 2015 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
    Commented Sep 19, 2015 at 14:17
12
\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}

enter image description here

1

The wheelchart package, which I wrote, can be used.

The percentage is defined by \n and is placed in the middle with the key middle.

The value is given by the first variable which is \n for the first slice and 100-\n for the second slice.

enter image description here

\documentclass[border=6pt]{standalone}
\usepackage{wheelchart}
\usepackage{siunitx}
\begin{document}
\begin{tikzpicture}
\def\n{85.34}
\wheelchart[
  data=,
  middle={\Huge\qty{\n}{\percent}},
  radius={1.5}{2}
]{%
  \n/violet!70,
  {100-\n}/black!50%
}
\end{tikzpicture}
\end{document}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .