1

I'm trying to make a bar graph with the text above its corresponding rectangle but I'm not able to change the vertical spacing between each rectangle.

enter image description here

Here's the code snippet:

\documentclass{standalone}

\RequirePackage{tikz}

\definecolor{white}{RGB}{255,255,255}
\definecolor{mainblue}{HTML}{0E5484}
\definecolor{maingray}{HTML}{B9B9B9}

\begin{document}

\newcommand\skills[1]{ 
    \renewcommand{\skills}{
        \begin{tikzpicture}
            \foreach [count=\i] \x/\y in {#1}{
                \draw[fill=maingray,maingray] (0,\i) rectangle (6,\i+0.4);
                \draw[fill=white,mainblue](0,\i) rectangle (\y,\i+0.4);
                \node [above right] at (0,\i+0.4) {\x};
            }
        \end{tikzpicture}
    }
}

\skills {{C++ / 4}, {JavaScript, HTML, CSS / 4}, {Java / 6}}
\skills % Needed to output the text

\end{document} 

Basically what I'm trying to do is have a for-each loop for every skill (e.g. Java) since I have more than those 3 and typing it in manually takes forever.

The problem now is that the rectangles are drawn by \draw and the node is the text.

I've tried some shenanigans with:

\usetikzlibrary{positioning} and \begin{tikzpicture}[node distance = 1cm] ...

but that's exclusively for nodes, so not my rectangles but only the text.

The best idea would be probably to make the rectangle become a node as well, including the text, but I don't know how to do that.

If anyone knew how to add some spacing I would appreciate it!

2

Welcome to TeX.SE!

I propose two solutions. In both cases, you can tune the vertical separation between skills with \skillstretchfactor. I prefer avoiding the \renewcommand inside \newcommand (I don't want to have to use ## or even #### to access macro parameters, unless in cases where this is really needed), especially redefining a macro using the same name but different semantics. In order to do this, I define a \declareskills macro that stores the current skills in a macro named \skills. This macro is later expanded by \typesetskills when you want to typset them.

Note: don't forget to type C\# for a skill such as C#, because the # character is special for TeX (it is used for parameter tokens and can't be input as is in text).

For the positioning of labels relatively to the “skills bars”, I use anchor=base west which ensures that the vertical distance from a label baseline to the corresponding skill bar doesn't depend on whether the label text contains descenders (letters like p, q or j that extend below the baseline). That wouldn't be the case with your above right. Also, I added inner sep=0, otherwise there is horizontal and vertical padding around the node text (the horizontal padding implies that the node text wouldn't be quite left-aligned with the bar—this is clearly visible on your screenshot).

Basic solution that keeps your rectangle commands

This is close to your code, but has the few improvements mentioned above.

\documentclass{article}
\usepackage{tikz}
\usepackage{xcolor}

\definecolor{mainblue}{HTML}{0E5484}
\definecolor{maingray}{HTML}{B9B9B9}

% Make sure no loaded package defines \skills
\newcommand{\skills}{}

\newcommand*{\declareskills}[1]{%
  \renewcommand*{\skills}{#1}%
}

\newcommand*{\skillstretchfactor}{1.2} % vertical positioning

\newcommand{\typesetskills}{%
  \begin{tikzpicture}
    \foreach [count=\i] \name/\score in \skills {
      \pgfmathsetmacro{\vpos}{-\skillstretchfactor*\i}
      \filldraw[maingray] (0,\vpos) rectangle (6,\vpos+0.4);
      \filldraw[mainblue] (0,\vpos) rectangle (\score,\vpos+0.4);
      \node[inner sep=0, anchor=base west] at ([yshift=0.8ex]0,\vpos+0.4) {\name};
    }
  \end{tikzpicture}%
}

\begin{document}

\declareskills{{C++ / 4}, {JavaScript, HTML, CSS / 4}, {Java / 6}}
\typesetskills % Print the skills diagram

\end{document}

Screenshot

Solution with the rectangle split shape

In this second solution, each rectangle is a node of shape rectangle split, consisting of two parts (the first filled with mainblue, the second with maingray, as you guessed). The width and height of the skill bars can be configured with \skillbarwidth and \skillbarheight, the maximal score (corresponding to 100% of a skill bar width) with \skillmaxscore.

\documentclass{article}
\usepackage{xcolor}
\usepackage{tikz}
\usetikzlibrary{shapes.multipart}

\definecolor{mainblue}{HTML}{0E5484}
\definecolor{maingray}{HTML}{B9B9B9}

\newdimen\scorewidth
\newlength{\skillbarwidth}
\newlength{\skillbarheight}

% Make sure no loaded package defines \skills
\newcommand{\skills}{}

\newcommand*{\declareskills}[1]{%
  \renewcommand*{\skills}{#1}%
}

\newcommand*{\skillstretchfactor}{1.2} % vertical positioning
\setlength{\skillbarwidth}{6cm}
\setlength{\skillbarheight}{12pt}
\newcommand*{\skillmaxscore}{6}

\newcommand*{\oneskill}[3]{%
  % The 'rectangle split' (with two parts)
  \node[skillstyle={#2}] (skill-\i) at (0, -\skillstretchfactor*#3)
    {
     % Length of the score rectangle. It needs to be set globally if one wants
     % to use it after \nodepart{second} (the current group will be finished).
     \global\scorewidth=\dimexpr \skillbarwidth*(#2)/\skillmaxscore\relax
     \phantom{\rule{\scorewidth}{\skillbarheight}}%
     % Complementary width for the second part
     \nodepart{second}\kern\dimexpr\skillbarwidth - \scorewidth\relax
   };
  % The label
  \node[inner sep=0, anchor=base west] at ([yshift=0.8ex]skill-\i.north west)
    {#1};
}

\newcommand{\typesetskills}{%
  \begin{tikzpicture}[skillstyle/.style={
      inner sep=0,
      rectangle split, rectangle split horizontal, rectangle split parts=2,
      rectangle split ignore empty parts,
      rectangle split part fill={mainblue, maingray}
      }]

    \foreach [count=\i] \name/\score in \skills {
      \oneskill{\name}{\score}{\i}
    }
  \end{tikzpicture}%
}

\begin{document}

\declareskills{{C++ / 4}, {JavaScript, HTML, CSS / 4}, {Java / 6}}
\typesetskills % Print the skills diagram

\end{document}

The output is the same as in the above screenshot.

| improve this answer | |
  • That's exactly what I was looking for, thank you very much! – RaCara Jul 23 '19 at 18:00
  • Glad to hear that. I've simplified the code in both examples, swapped them to start with the simpler one, and added \skillbarwidth and \skillbarheight length parameters to the example that uses the rectangle split shape. – frougon Jul 23 '19 at 20:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.