1

I'm working on adapting the code from How to Optimize a TikZ Animation of Quicksort? to use TikZ with layers.

I want to add a layer that draws a rectangle with a very thick line. Additionally, I would like to include a line between the 7th and 8th elements, exactly in the middle of the vector.

Furthermore, the labels should be positioned between the colored cells. More details are provided in the code.


Desired output

This is my current output: actual output

This is the output I would like to achieve: desired output


Code
\documentclass[tikz, border=.2cm]{standalone} \usetikzlibrary{chains} % slide 11/52 \newcommand*\tikzqsset{\pgfqkeys{/tikz/qs}} \tikzqsset{ % default cell style vector/.style = {draw, shape=rectangle, minimum size = +0.7cm, outer sep = +0pt}, label/.style = {node distance = 0pt,font = \ttfamily\scriptsize}, % /tikz/label exists already % cells styles undiscovered/.style = {fill = white}, left/.style = {fill = red!30}, between/.style = {fill = yellow!30}, right/.style = {fill = blue!30}, % parsing style parse/.style args={#1#2}{qs/sc-#1/.try, node contents={#2}}, % defining styles sc-l/.style={in front of path, qs/undiscovered}, sc-L/.style={in front of path, qs/left}, sc-b/.style={in front of path, qs/between}, sc-r/.style={in front of path, qs/undiscovered}, sc-R/.style={in front of path, qs/right}, } \NewDocumentCommand{\DividiEtImpera}{ m }{ \tikz\path[node distance=+0pt, start chain=going right] { foreach[count=\i] \v in {#1}{ node[on chain, qs/vector, qs/parse/.expand once=\v] } } []; \tikz\draw[very thick] (chain-1.north west) rectangle (chain-16.south east); } \begin{document} \DividiEtImpera{l0, L1, L2, L3, L4, l5, b6, b7, b8, b9, b10, r11, r12, R13, R14, R15} % maxL label below and between 1 and 4 % maxRR label below and between 6 and 7 % maxLL label below and between 8 and 10 % maxR label below and between 13 and 15 \end{document} 
6
  • Why do you explicitly set the node contents in parse/.style args={#1#2}{qs/sc-#1/.try, node contents={#2}}? if you want the spacing, just use \phantom{#2} or whatever. Commented Feb 4 at 2:09
  • why do you have things in two separate tikz commands? I would think you would want a single environment. then you could annotate by adding nodes for labels etc. in the usual way? Commented Feb 4 at 2:12
  • Do you even need the numbers for anything? You can just draw colored squares based on l, L, L, .... Are the max-labels fixed? Shouldn't they move if you change the input? Commented Feb 4 at 12:36
  • I've added the numbers only to make the question clearer :) Commented Feb 4 at 13:22
  • Labels shouldn't be fixed; I think that @Digamma's approach is what I had in mind. Commented Feb 4 at 13:26

1 Answer 1

3

As cfr said, you should use the tikzpicture environment instead of \tikz.

I drew a thick rectangle around the entire structure and a vertical line between 7 and 8. Also, I used the calc and positioning library to compute midpoints for label placement below specified cell ranges.

output

\documentclass[tikz, border=.2cm]{standalone} \usetikzlibrary{chains, calc, positioning} \newcommand*\tikzqsset{\pgfqkeys{/tikz/qs}} \tikzqsset{ vector/.style = {draw, shape=rectangle, minimum size=0.7cm, outer sep=0pt}, label/.style = {font=\ttfamily}, undiscovered/.style = {fill=white}, left/.style = {fill=red!30}, between/.style = {fill=yellow!30}, right/.style = {fill=blue!30}, parse/.style args={#1#2}{qs/sc-#1/.try, node contents={#2}}, sc-l/.style = {qs/undiscovered}, sc-L/.style = {qs/left}, sc-b/.style = {qs/between}, sc-r/.style = {qs/undiscovered}, sc-R/.style = {qs/right}, } \NewDocumentCommand{\DividiEtImpera}{ m }{ \begin{tikzpicture} \path[node distance=0pt, start chain=going right] foreach [count=\i] \v in {#1} { node[on chain, qs/vector, qs/parse/.expand once=\v] (chain-\i) {} }; \begin{scope}[line width=1.2pt] \draw (chain-1.north west) rectangle (chain-16.south east); \draw (chain-9.west |- chain-1.north) -- (chain-9.west |- chain-16.south); \end{scope} \coordinate (maxL) at ($(chain-2.west)!0.5!(chain-5.east)$); \node[qs/label, below=4mm] at (maxL) {maxL}; \coordinate (maxRR) at ($(chain-7.west)!0.5!(chain-8.east)$); \node[qs/label, below=4mm] at (maxRR) {maxRR}; \coordinate (maxLL) at ($(chain-9.west)!0.5!(chain-11.east)$); \node[qs/label, below=4mm] at (maxLL) {maxLL}; \coordinate (maxR) at ($(chain-14.west)!0.5!(chain-16.east)$); \node[qs/label, below=4mm] at (maxR) {maxR}; \end{tikzpicture} } \begin{document} \DividiEtImpera{l, L, L, L, L, l, b, b, b, b, b, r, r, R, R, R} \end{document} 

As you can see, the entire structure is enclosed with a \draw[very thick] rectangle. A vertical line is drawn between 7 and 8 using their chain references. Labels are placed below calculated midpoints using the calc and positioning library for precise alignment under specified cell ranges.

4
  • I’m not sure why, but the coordinates don’t seem to be exactly in the middle of the nodes; they appear slightly to the left :/ Commented Feb 4 at 14:36
  • For example, the first label is centered after changing the coordinate from $(chain-1.west)!.5!(chain-4.east)$ to $(chain-1.west)!.5!(chain-6.east)$. Commented Feb 4 at 14:39
  • 1
    @EmanueleNardi it should be centered now. If it isn't, try adjusting the values. Commented Feb 4 at 15:21
  • I understood what the problem was: TikZ starts counting from 1, not from 0. Commented Feb 4 at 16:20

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.