3

I'm still getting started with tikzpicture. Here's the result I want to obtain with it in a automatically-fancy code

wannabe

This is what I'm up to though. I can't even get past this:

result

Here is my MWE.

\documentclass[standalone]
\usepackage{standalone}
\usepackage{pgf}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{positioning}

\newcommand\vectorcell[5]   {\draw[fill=#3] (#5) rectangle +(#1,#2);
                       \node[font=\sffamily\bfseries] at ($(#5)+({0.5*#1},{0.5*#2})$) {#4};
                       \node[font=\sffamily] at ($(#5)+({0.5*#1+5},{0.5*#2})$) {\texttt{threadIdx.x = }#4};
                      }
\newcommand\cell[1]       {\vectorcell{1}{1}{gray!30}{#1}}

\begin{document}

\begin{figure}
\begin{tikzpicture}[scale=0.5]%
\foreach \j in {0,1,2}%souldn't I remove the following semicolon?
    \node[font=\sffamily] at (12,4.1*\j+1.0) {\texttt{blockIdx.x = }\j};
    \foreach \i in {0,...,3}%
        \cell{\i}{0,1.1*\i+0.5};
\end{tikzpicture}
\end{figure}

\end{document}

My issue is I can't put the second foreach to work: I supposed it's the semicolon stated above. If I remove it the code doesn't compile, while if I keep it I only get one column of threads, so it sure isn't.

My questions are two:

  • How can I have tikz create one column of threadIdx.x perblockIdx.xindex?
  • How can I rotate then theblockIdx.xlabel?

On a side note, what about the curly braces? I believe with the answers above I can do it myself though.

5

\foreach can be used as \foreach \i in {0,1,2} { \foo{\i} }, where the last brace gives the scope of what is repeated for each iteration of \i. Using this we can rewrite

\foreach \j in {0,1,2}%souldn't I remove the following semicolon?
    \node[font=\sffamily] at (12,4.1*\j+1.0) {\texttt{blockIdx.x = }\j};
    \foreach \i in {0,...,3}%
        \cell{\i}{0,1.1*\i+0.5};
\end{tikzpicture}

as

\foreach \j in {0,1,2} {
    \node[font=\sffamily] at (12,4.1*\j+1.0) {\texttt{blockIdx.x = }\j};
    \foreach \i in {0,...,3} {
        \cell{\i}{0,1.1*\i+0.5};
    }
}

where now the second loop runs for each value of \j, although right now \cell{\i}{0,1.1*\i+0.5}; will just print the same thing in the same place three times, we can tell it to position the cells according to the value of \j using \cell{\i}{0,4.1*\j+1.1*\i+0.5};.

At this point we have

enter image description here

so we can see that the \foreach parts of the code are running as intended (although spacing needs a bit of adjustment).

Using Jake's answer to Draw Curly Braces in TikZ we can then add the braces along with passing the rotate=-90 option to the node to get close to the intended diagram.

enter image description here

(I misread the diagram when doing this part so there's a correction added below)

Finally though the "thread" labels are only following the \i index. In order to do the necessary maths we need to change \vectorcell replacing #4 in the definition with \pgfmathparse{int(#4)}\pgfmathresult will give the integer value of the first argument given to \cell so we can now do maths there. Finally to get ascending numbers as we go down, the easiest way (one could re-work some of the code instead...) is simply to pass [yshift=-1] as an option to the tikzpicture environment (this necessitates removal of the mirror option passed to the braces).

Thus we have

enter image description here

Produced from

\documentclass[tikz]{standalone}
\usetikzlibrary{calc,decorations.pathreplacing,positioning}

\newcommand\vectorcell[5]{\draw[fill=#3] (#5) rectangle +(#1,#2);
                       \node[font=\sffamily\bfseries] at ($(#5)+({0.5*#1},{0.5*#2})$) {\pgfmathparse{int(#4)}\pgfmathresult};
                       \node[font=\sffamily] at ($(#5)+({0.5*#1+5},{0.5*#2})$) {\texttt{threadIdx.x = }\pgfmathparse{int(#4)}\pgfmathresult};
                      }
\newcommand\cell[2]{\vectorcell{1}{1}{gray!30}{#1}{#2}}

\begin{document}
\begin{tikzpicture}[scale=0.5,yscale=-1]
\foreach \j in {0,1,2}{
    \draw [decorate,decoration={brace,amplitude=10pt,raise=4pt},yshift=0pt] (8.5,6*\j+0.5) -- (8.5,6*\j+4.8) node [black,midway,xshift=0.8cm,rotate=-90] {\texttt{blockIdx.x = }\j};
    \foreach \i in {0,...,3}{
        \cell{\i+4*\j}{0,6*\j+1.1*\i+0.5};
    }
}
\end{tikzpicture}
\end{document}

(More of an aside: I don't understand why you have \newcommand\cell[1]{\vectorcell{1}{1}{gray!30}{#1}} when \vectorcell takes five mandatory arguments, \newcommand\cell[2]{\vectorcell{1}{1}{gray!30}{#1}{#2}} makes more sense to me, so I've changed to that above.)


Ok, so the labelling grey blocks should follow 4*\j+\i while the thread numbers should only follow \i. Given the \cell macro is only called once, probably the simplest way for now is to just "unpack" it and place it all directly in the foreach macros as

\documentclass[tikz]{standalone}
\usetikzlibrary{calc,decorations.pathreplacing,positioning}

\begin{document}
\begin{tikzpicture}[scale=0.5,yscale=-1]
\foreach \j in {0,1,2}{
    \draw [decorate,decoration={brace,amplitude=10pt,raise=4pt},yshift=0pt] (8.5,6*\j+0.5) -- (8.5,6*\j+4.8) node [black,midway,xshift=0.8cm,rotate=-90] {\texttt{blockIdx.x = }\j};
    \foreach \i in {0,...,3}{
        \draw[fill=gray!30] (0,6*\j+1.1*\i+0.5) rectangle +(1,1);
        \node[font=\sffamily\bfseries] at ($(0,6*\j+1.1*\i+0.5)+(0.5,0.5)$) {\pgfmathparse{int(4*\j+\i)}\pgfmathresult};
        \node[font=\sffamily] at ($(0,6*\j+1.1*\i+0.5)+(5.5,0.5)$) {\texttt{threadIdx.x = }\pgfmathparse{int(\i)}\pgfmathresult};
    }
}
\end{tikzpicture}
\end{document}

enter image description here

where \i alone is used to label the threads and 4*\j+\i is used for the blocks.

One could even avoid the calculation of where to place the number inside the box by using

\draw[fill=gray!30] (0,6*\j+1.1*\i+0.5) rectangle +(1,1)
    node [midway, font=\sffamily\bfseries] {\pgfmathparse{int(4*\j+\i)}\pgfmathresult};

to automatically center the node within the rectangle which has just been drawn.

Perhaps even that node could be labelled itself so that the threadIdx.x = node is placed relative to that, i.e.

\draw[fill=gray!30] (0,6*\j+1.1*\i+0.5) rectangle +(1,1)
    node (boxnumber-\i-\j) [midway, font=\sffamily\bfseries] {\pgfmathparse{int(4*\j+\i)}\pgfmathresult};
\node[font=\sffamily] at ($(boxnumber-\i-\j)+(5,0)$) {\texttt{threadIdx.x = }\pgfmathparse{int(\i)}\pgfmathresult};

Not that these are necessary for it to work, or even that much nicer to look at.

However, I have now removed the \newcommands that you had earlier, maybe wrapping the drawing steps up in a macro is what you want. I think using a two-macro \cell command to pass a coordinate and one value from the counters is a non-starter, both need to be input separately (or two linearly-independent combinations at least). So as a basic we need

\newcommand{\thread}[3]{
    \draw[fill=gray!30] (#3) rectangle +(1,1)
        node (boxnumber-#1) [midway, font=\sffamily\bfseries] {\pgfmathparse{int(#1)}\pgfmathresult};
    \node[font=\sffamily] at ($(boxnumber-#1)+(5,0)$) {\texttt{threadIdx.x = }\pgfmathparse{int(#2)}\pgfmathresult};
}

If there is a need to change the box size or colour, this could be done as additional arguments (possibly optional, or even key-val). I would suggest add the box size as a single argument expecting two values separated by a comma - namely a coordinate.

\newcommand{\thread}[5][gray!30]{
    \draw[fill=#1] (#5) rectangle +(#2)
        node (boxnumber-#3) [midway, font=\sffamily\bfseries] {\pgfmathparse{int(#3)}\pgfmathresult};
    \node[font=\sffamily] at ($(boxnumber-#3)+(5,0)$) {\texttt{threadIdx.x = }\pgfmathparse{int(#4)}\pgfmathresult};
}

Perhaps grouping the blockIdx label and the inner foreach into a single command might be useful, given there's no use-case given, I'll stop suggesting things with ever more tenuous usefulness.

  • Thank you very much. Tikz is so powerful yet so difficult for beginners – Eugenio Feb 14 '17 at 21:13
  • Hang on, I noticed just now: the threadIdx.x index must run from 0 to 4 within all of the braces, it need not to be the same as the cells – Eugenio Feb 14 '17 at 21:45
  • @Eugenio misread the diagram, see my edit. – Dai Bowen Feb 14 '17 at 23:08
2

I'm not completely sure where you are heading. So far your application doesn't look like a typical use case for tikz, except maybe for the grey box. Here is another way to achieve what you show, to give you some ideas.

enter image description here

\documentclass{article}
\usepackage{tikz}
\newcommand\boxed[1]% enclose #1 in a grey box
   {\tikz[baseline=(X.base)]
      \node[draw,fill=gray!30,inner sep=1pt,minimum width=1.4em,minimum height=2ex]
        (X){\scriptsize\bfseries\sffamily#1};%
   }
\newcommand\threadIdx[2]% #1 = index of block, #2 = offset
   {\pgfmathparse{#1*4+#2}%
    \let\tmp\pgfmathresult
    \boxed{\pgfmathprintnumber[assume math mode=true]{\tmp}}\quad
    \texttt{threadIdx.x = }{\textsf{#2}}%
   }
\newcommand\threadIdxs[1]% #1 = index of block
   {$\left.
    \renewcommand\arraystretch{1.2}
    \begin{tabular}{l}
    \threadIdx{#1}{0}\\
    \threadIdx{#1}{1}\\
    \threadIdx{#1}{2}\\
    \threadIdx{#1}{3}
    \end{tabular}
    \right\}
    \rotatebox[origin=c]{270}{\scriptsize\texttt{blockIdx.x = }{\textsf{#1}}}
    $%
   }
\begin{document}
\foreach \i in {0,1,2} {\threadIdxs{\i}\medskip\par}
\end{document}
  • Thank you for pointing that out; your answer is perfectly clear, the thing is I want to get used to tikz, I feel like it will be useful to me in the following years. Thx anyway – Eugenio Feb 14 '17 at 20:35
2
  • two foreach loops: outer for blockIdx groups, inner for threadIdx elements
  • blocks, numbered from 0 to 11 (or more, if it is required) are defined as nodes
  • for placing of nodes is used chains package, consequently no nodes' positions calculations
  • for braces, that it appearance is more fancy, is used library calligraphy

MWE:

\documentclass[tikz,margin=3mm]{standalone}
\usetikzlibrary{calc, chains, decorations.pathreplacing, calligraphy, positioning}

\begin{document}
    \begin{tikzpicture}[
node distance = 1mm and 11mm,
  start chain = going below,
  lbox/.style = {font=\normalsize\ttfamily, sloped},%labels style
   box/.style = {draw, fill=gray!30, minimum size=7mm, font=\large\sffamily, 
                 label={[lbox,xshift=7mm]right:threadIdx.x = \j},
                 on chain}
                    ]
\foreach \i [count=\ii from 0] in {0,4,8}% <-- outer loop, determine blockIdx
{
    \foreach \j [count=\k from \i] in {0,1,2,3}% <-- inner loop, determine threadIdx
{
\ifnum\j=0 \node (n\j) [box,yshift=-3mm] {\k}% <-- for separating blockIdx
    \else
           \node (n\j) [box] {\k}
\fi;
}
\draw[decorate, decoration={calligraphic brace, amplitude=6pt,
                pre=moveto, pre length=1pt, post=moveto, post length=1pt,
                raise=42mm},
                draw, thick, pen colour={red}]
      (n0.north) -- node[lbox,above=44mm] {blockIdx.x = \ii} (n3.south);
}
\end{tikzpicture}
\end{document}

enter image description here

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.