43

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}
\usetikzlibrary{calc,shadows}

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

1
  • 1
    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. Feb 18, 2011 at 9:28

5 Answers 5

59

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}

ranking stars with tikz


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}
\score{0}{5} That's appalling!

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

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

\end{document}

enter image description here

7
  • 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. Feb 18, 2011 at 16:06
  • 1
    Blast, I've already voted for this before your edit. I think that the floating point version is fantastic. Feb 18, 2011 at 18:24
  • That is brilliant. Wow.
    – Robbie
    Feb 20, 2011 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?
    – Robbie
    Feb 20, 2011 at 12:18
  • @zoqaeski: Done! Just use relative lengths ("ex" and "em") for the size and spacing.
    – Jake
    Feb 20, 2011 at 20:06
16

enter image description here

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);

add(score(scoreMark=1,star,maxscore=7),(0,0));
add(score(scoreMark=2,star,maxscore=7,linePen=lightred,bgPen=lightblue),(0,-3sc));
add(score(scoreMark=3.5,star,maxscore=5,linePen=lightred,bgPen=lightblue),(0,-6sc));
add(score(scoreMark=3.75,star,maxscore=4,linePen=olive,bgPen=white,scorePen=lightgreen),(0,-9sc));

add(score(4.2,bgPen=green+opacity(0.3),scorePen=red+opacity(0.5)),(0,3sc));

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

0
14

With PSTricks.

enter image description here

\documentclass[preview,border=12pt,varwidth]{standalone}
\usepackage{pstricks}
\usepackage{multido}
\SpecialCoor
\makeatletter
\def\LoadPSVars{\pstVerb{/ptcm {\pst@number\psunit div} bind def}}
\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)
    \LoadPSVars
    \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!
2
  • 3
    TikZ, I am sorry. It is just an example! Apr 14, 2013 at 10:02
  • 1
    @armpit: do you still keep that opinion (100 PSTricks, 50 Asymptote, 20 Metapost, 5 TikZ)? ^^
    – Black Mild
    Nov 20, 2018 at 17:26
11

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:

enter image description here

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

3
  • Hi Aditya, I'm interested in learning a little about MetaPost, and this looks like a nice application of that. However, I wish that your module did support fractional values. How hard would it be to add? Jan 11, 2020 at 6:43
  • @faheem: it is relatively easy to add support from fractional values. The module provides a few different counters and fractional values don't make sense for some of them, but for makers it is relatively easy to get. I'll upload an updated version of the module and then reply here
    – Aditya
    Jan 11, 2020 at 14:46
  • Thank you very much, Aditya. I look forward to experimenting with MetaPost. Or is it MetaFun now? Jan 11, 2020 at 16:09
6

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);
8
  • 1
    ... 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?) Feb 18, 2011 at 13:07
  • @Matthew: Can you please tell a TikZ noob how to include this into Jake's code? Feb 18, 2011 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. Feb 18, 2011 at 13:44
  • 1
    @Matthew: Consider yourself asked. Feb 18, 2011 at 13:47
  • 3
    @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. Feb 18, 2011 at 16:00

You must log in to answer this question.

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