# Drawing stars/similar with Tikz

I'm writing a review for a book at the moment, and I thought I'd be clever and show off what LaTeX is capable of by adding a x-out-of-y stars graphic. Tikz can do many things so I would have thought that a trick like this would be fairly trivial, however it seems that I cannot figure out a macro to draw the shapes at the right size, let alone fancy tricks such as half-filled stars or something similar. I think the code I have so far might be headed in the right direction:

\usepackage{tikz}
\usetikzlibrary{shapes.geometric}

\newcommand*\starfill{%
\tikz[baseline=(key.base),scale=-3]
\node[star, star points=5, star point ratio=2.25, fill=black, draw](key) {S};
}


I've tried to start by drawing a single star shape, but ideally I'd like to define like \starsranking{number}{total} that will output the appropriate shaded number of stars out of total. Is this doable? It doesn't sound particularly difficult.

-
The star, star points=5, star point ratio=2.25 are your own options, aren't there? You should have a look at \foreach. You need two: one from 1 to \starpoints to make the filled stars and one for \starpoints+1 to 5. The half-filled stars should be do-able with an clipped fill-path. –  Martin Scharrer Feb 18 '11 at 9:28

Here's the code for fully filled stars, now slightly improved thanks to Andrew Stacey's answer to the checkerboard question:

\documentclass{minimal}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric}

\newcommand\score[2]{
\pgfmathsetmacro\pgfxa{#1+1}
\tikzstyle{scorestars}=[star, star points=5, star point ratio=2.25, draw,inner sep=1.3pt,anchor=outer point 3]
\begin{tikzpicture}[baseline]
\foreach \i in {1,...,#2} {
\pgfmathparse{(\i<=#1?"yellow":"gray")}
\edef\starcolor{\pgfmathresult}
\draw (\i*1.75ex,0) node[name=star\i,scorestars,fill=\starcolor]  {};
}
\end{tikzpicture}
}

\begin{document}
\score{0}{5} A meagre result.

\score{4}{5} Much better

\score{5}{5} Perfect score!

\end{document}


And here's the much more elaborate, much more pointless, floating point scoring star macro (I'll leave the simple one in as well, it's a lot more usable):

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric,calc}

\newcommand\score[2]{
\pgfmathsetmacro\pgfxa{#1+1}
\tikzstyle{scorestars}=[star, star points=5, star point ratio=2.25, draw,inner sep=0.15em,anchor=outer point 3]
\begin{tikzpicture}[baseline]
\foreach \i in {1,...,#2} {
\pgfmathparse{(\i<=#1?"yellow":"gray")}
\edef\starcolor{\pgfmathresult}
\draw (\i*1em,0) node[name=star\i,scorestars,fill=\starcolor]  {};
}
\pgfmathparse{(#1>int(#1)?int(#1+1):0}
\let\partstar=\pgfmathresult
\ifnum\partstar>0
\pgfmathsetmacro\starpart{#1-(int(#1))}
\path [clip] ($(star\partstar.outer point 3)!(star\partstar.outer point 2)!(star\partstar.outer point 4)$) rectangle
($(star\partstar.outer point 2 |- star\partstar.outer point 1)!\starpart!(star\partstar.outer point 1 -| star\partstar.outer point 5)$);
\fill (\partstar*1em,0) node[scorestars,fill=yellow]  {};
\fi

,\end{tikzpicture}
}

\begin{document}
\small\score{2}{5} A meagre result.

\Huge{\score{4.4}{5} Wooo!}

\end{document}


-
Like I said, very good (even better since I first said it). I didn't realize coordinates could be averaged with the ! like colors can. I had been going for a style approach so that you could type \node[scorestars,portion=0.25] and get 25% of the star filled. Looks like you could use the append after command key for that. –  Matthew Leingang Feb 18 '11 at 16:06
Blast, I've already voted for this before your edit. I think that the floating point version is fantastic. –  Loop Space Feb 18 '11 at 18:24
That is brilliant. Wow. –  zoqaeski Feb 20 '11 at 12:11
One question though: is it possible to make the stars scale to the text height? So if the text is \large the stars will also be correspondingly bigger? –  zoqaeski Feb 20 '11 at 12:18
@zoqaeski: Done! Just use relative lengths ("ex" and "em") for the size and spacing. –  Jake Feb 20 '11 at 20:06

Asymptote version stars.asy:

size(200);
real sc=20;

picture score(real scoreMark=0,guide star=scale(sc)*unitcircle, int maxscore=5,
pen linePen=nullpen, pen bgPen=darkblue, pen scorePen=orange){
picture pic;
guide[] g;
for(int i=0;i<maxscore;++i){
g.push(shift((2sc*i,0))*star);
}
assert(maxscore>0 && scoreMark>=0 && scoreMark<=maxscore,"***** Wrong score.");
fill(pic,box((-sc,-sc),(maxscore*2sc-sc,sc)),bgPen);
fill(pic,box((-sc,-sc),(scoreMark*2sc-sc,sc)),scorePen);
clip(pic,g);
draw(pic,g,linePen);
return pic;
}

guide star;
pair p;
for(int i=0;i<5;++i){
p=rotate(72*i)*N;
star=star--p;
star=star--(scale(0.382)*rotate(72*i+36)*N);
}
star=scale(sc)*(star--cycle);



To get a standalone stars.pdf run asy -f pdf stars.asy.

-
+1. Very nice!!! –  stalking isn't tolerated Apr 14 '13 at 16:32

I have written a package for ConTeXt that draws X out of Y graphics. It is primarily meant to draw numbers in presentations. It offers stars as one of the options:

\usemodule[visualcounter]

\definepalet
[star-colors]
[active=yellow,
past=yellow,
future=gray]

\definevisualcounter
[stars]
[markers]
[mpsetups=visualcounter::markers:star,
width=1.5EmWidth,
distance=0.25EmWidth,
palette=star-colors,
]

\starttext

\startTEXpage[offset=2mm]
\startitemize
\item \usevisualcounter[n=1, last=5]{stars} That's appalling!
\item \usevisualcounter[n=2, last=5]{stars} A meagre result.
\item \usevisualcounter[n=4, last=5]{stars} Woo!
\stopitemize
\stopTEXpage
\stoptext


See documentation for more details.

As the primary purpose of this module is to display page numbers, it does not support fractional values.

-

With PSTricks.

\documentclass[preview,border=12pt,varwidth]{standalone}
\usepackage{pstricks}
\usepackage{multido}
\SpecialCoor
\makeatletter
\makeatother

\def\points{}
\def\Star{%
\xdef\points{}% cleaning
\multido{\iR=0+72,\ir=36+72}{5}{\xdef\points{\points (10pt;\iR)(5pt;\ir)}}
\expandafter\pspolygon\points}

\def\Rating#1{% #1: percentage
\psscalebox{0.35}{%
\begin{pspicture}(11pt,-11pt)(111pt,11pt)
\psclip{\pscustom{\psLoop{5}{\translate(20pt,0)\Star}}}
\psframe*[linecolor=yellow](11pt,-11pt)(!#1 11 add ptcm 11 ptcm)
\endpsclip
\pscustom{\psLoop{5}{\translate(20pt,0)\Star}}
\end{pspicture}}}

\begin{document}
\begin{enumerate}
\item \Rating{100} PSTricks
\item \Rating{50} Asymptote
\item \Rating{20} Metapost
\item \Rating{5} TikZ
\end{enumerate}
\end{document}


## Warning:

• \rput will not work inside \pscustom. Use \translate instead!
• standalone discards my ptcm operator defined in the preamble, so I have to load it manually inside pspicture. It is sad!
-
TikZ, I am sorry. It is just an example! –  stalking isn't tolerated Apr 14 '13 at 10:02

Jake's answer is very good. Here's the extra half star:

\node[scorestars,fill=gray] {};
\path node[scorestars,fill=yellow] (s) {} [clip] (s.south west) rectangle (s.north);

-
... and here's half a vote. Oh, wait, they don't come in half steps yet so you'll have to have a whole one. (Incidentally, why isn't your name in the list of moderator candidates?) –  Loop Space Feb 18 '11 at 13:07
@Matthew: Can you please tell a TikZ noob how to include this into Jake's code? –  Hendrik Vogt Feb 18 '11 at 13:15
@Andrew: LOL. I only gave half an answer hoping that Jake could run with it and improve his answer. I already spent an hour trying to make a customizable portion of the star filled so I think I should quit for now. –  Matthew Leingang Feb 18 '11 at 13:44
@Matthew: Consider yourself asked. –  Loop Space Feb 18 '11 at 13:47
@Jake: True that. look at the bright side. You've got 70 rep so far out of it. That and \$2.25 will buy you a cup of coffee at Starbucks. –  Matthew Leingang Feb 18 '11 at 16:00