3

I borrowed code from here for this question. The code was used to draw a hexagram (e.g.䷊), of which each stroke is corresponding to a binary digit from a list (e.g. {1,0,1,1,1,1}). A foreach loop against the list was used to draw either a full ( ⚊ if 1) or broken stroke ( ⚋ if 0). How can I use the first 3 numbers from the list as color [e.g. rgb(0,0,0)] for the first 3 strokes, and the last 3 for second set of trigram.

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{math}
\usepackage{ifthen}

\begin{document}
\begin{tikzpicture}
\tikzset{
hexagram/.pic={
  \edef\set{#1}   
  \foreach \d [count=\n] in \set{
    % \foreach \d [count=\n] in {#1}{
    \ifthenelse{\d=0}
    {\draw [yshift=\n*2cm, line width=1cm] (-6,0) -- (-1,0)  (1,0) -- (6,0);}
    {\draw [yshift=\n*2cm, line width=1cm] (-6,0) -- (6,0);}
  }}
 }
\foreach [count=\n] \m in {
  {0, 0, 0, 0, 0, 0}, 
  {0, 0, 0, 0, 0, 1}, 
  {0, 0, 0, 1, 1, 1}}{
  \pic at (\n*15,0) {hexagram = \m};
}
\end{tikzpicture}
\end{document}
Tony Tan
  • 353
  • I think I did not made myself clear. What I want is the first trigram in one color and second one in another, e.g. ䷊, the top 3 broken strokes in black [rgb(0,0,0) ] and bottom 3 in white [ rgb(1,1,1)].. – Tony Tan Jan 31 '19 at 00:54

2 Answers2

3

This is a proposal. I first kicked out ifthen because it is not needed. Then I made the code seemingly more complicated by adding \smuggle. You could have a shorter code at the expense of making the intermediate list that defines the color global, but I didn't want to do that. But these are details.

The (updated) question is addressed by a macro \parsesplit which splits the list into two sublists. It works like

  \parsesplit(<long list with (at least) 6 entries>)->(<first>,<second>)

where first and second are the names of the macros in which the sublists are to be stored. In the MWE below these are \mycolone and \mycoltwo, which can then be used to define colors via

  \definecolor{mycol1}{rgb}{\mycolone}
  \definecolor{mycol2}{rgb}{\mycoltwo}

And this is the MWE. In this updated MWE, I removed the smuggling, and added something that allows you to scale the picture with a simple scale=....

\documentclass{standalone}
\usepackage{tikz}

\def\parsesplit(#1,#2,#3,#4,#5,#6)->(#7,#8){%
    \edef#7{#1,#2,#3}%
    \edef#8{#4,#5,#6}%
}
\begin{document}
\begin{tikzpicture}
\tikzset{
trigram/.pic={
    \edef\temp{\noexpand\parsesplit(#1)->(\noexpand\mycolone,\noexpand\mycoltwo)}
    \temp
  \pgfgettransformentries{\tmp}{\tmp}{\tmp}{\yscale}{\tmp}{\tmp}
  \definecolor{mycol1}{rgb}{\mycolone}
  \definecolor{mycol2}{rgb}{\mycoltwo}
  \foreach \d [count=\n] in #1{
    \ifnum\d=0
      \ifnum\n<4
        \draw [color=mycol1,yshift=\n*2cm, line width=\yscale*1cm] (-6,0) -- (-1,0)  (1,0) -- (6,0);
      \else
        \draw [color=mycol2,yshift=\n*2cm, line width=\yscale*1cm] (-6,0) -- (-1,0)  (1,0) -- (6,0);
      \fi   
    \else
      \ifnum\n<4
        \draw [color=mycol1,yshift=\n*2cm, line width=\yscale*1cm] (-6,0) -- (6,0);
      \else
        \draw [color=mycol2,yshift=\n*2cm, line width=\yscale*1cm] (-6,0) -- (6,0);
      \fi   
    \fi
  }  
  },}
\foreach [count=\n] \m in {
  {0, 1, 0, 0, 0, 0}, 
  {0, 0, 0, 0, 0, 1}, 
  {1, 0, 0, 1, 1, 1}}{
  \pic[scale=0.5] at (\n*15,0) {trigram = \m};
}
\end{tikzpicture}
\end{document}

enter image description here

OLD STUFF(may be useful for some):I am not sure if that's the correct interpretation so here is another one.

\documentclass{standalone}
\usepackage{tikz}
%% smuggling from https://tex.stackexchange.com/a/470979/121799
\newcounter{smuggle}
\DeclareRobustCommand\smuggleone[1]{%
    \stepcounter{smuggle}%
    \expandafter\global\expandafter\let\csname smuggle@\arabic{smuggle}\endcsname#1%
    \aftergroup\let\aftergroup#1\expandafter\aftergroup\csname smuggle@\arabic{smuggle}\endcsname
}
\DeclareRobustCommand\smuggle[2][1]{%
    \smuggleone{#2}%
    \ifnum#1>1
    \aftergroup\smuggle\aftergroup[\expandafter\aftergroup\the\numexpr#1-1\aftergroup]\aftergroup#2%
    \fi
}

\begin{document}
\begin{tikzpicture}
\tikzset{
hexagram/.pic={
    \foreach \d [count=\n] in #1{
    \ifnum\d=0
    \draw [yshift=\n*2cm, line width=1cm] (-6,0) -- (-1,0)  (1,0) -- (6,0);
    \else
    \draw [yshift=\n*2cm, line width=1cm] (-6,0) -- (6,0);
    \fi
  }},
trigram/.pic={
    \foreach \d [count=\n] in #1{
    \ifnum\n<4
      \ifnum\n=1
        \edef\collst{\d}
      \else
         \edef\collst{\collst,\d}
      \fi
    \else
      \pgfmathsetmacro{\mycol}{{\collst}[\n-4]}
      \ifnum\d=0
      \draw [color=\mycol,yshift=\n*2cm, line width=1cm] (-6,0) -- (-1,0)  (1,0) -- (6,0);
      \else
      \draw [color=\mycol,yshift=\n*2cm, line width=1cm] (-6,0) -- (6,0);
      \fi
    \fi 
    \smuggle{\collst}
  }},  
  }
\foreach [count=\n] \m in {
  {0, 0, 0, 0, 0, 0}, 
  {0, 0, 0, 0, 0, 1}, 
  {0, 0, 0, 1, 1, 1}}{
  \pic at (\n*15,0) {hexagram = \m};
}
\begin{scope}[yshift=-15cm]
\foreach [count=\n] \m in {
  {"blue","red","blue", 0, 0, 0}, 
  {"black","red","red", 0, 0, 1}, 
  {"blue","black","orange", 1, 1, 1}}{
  \pic at (\n*15,0) {trigram = \m};
}

\end{scope}
\end{tikzpicture}
\end{document}

enter image description here

  • 1
    Thanks for the update! It works fine without the \smuggle. – Tony Tan Jan 31 '19 at 06:24
  • How do I properly scale the hexagram? I tried scope in \tikzset and scale inside pic. The overall size scales, but not the stroke width. what am I missing? @marmot – Tony Tan Jan 31 '19 at 18:47
  • 1
    @TonyTan You are not missing anything, line widths do not get transformed like coordinates. This has already lead to confusion at other places. Luckily there is a simple fix: read out the transformation entries and apply them. Then you can simply use pic[scale=0.5], say. I edited the answer accordingly. And thanks for your comment on smuggling! (This is also in the edit.) –  Jan 31 '19 at 18:57
  • The line thickness is altered when I apply rotation and scale. ? @marmot – Tony Tan Feb 01 '19 at 23:37
  • 1
    @TonyTan My fix applied to the situation in the MWE. In general, there are 6 parameters that you get out of \pgfgettransformentries{\tmp}{\tmp}{\tmp}{\yscale}{\tmp}{\tmp}. The last two are translations and the first 4 are the elements of a transformation matrix. The 22 entry was the one that is relevant in this case. If you have a more complicated scenario, this may change. The probably simplest fix for all that would be not to draw lines but just fill rectangles as they will automatically transform correctly. –  Feb 01 '19 at 23:42
2

I made a little amendment in your code, I assume you can put another delimiter between the color and number, i.e. /.

    \documentclass{standalone}
    \usepackage{tikz}
    \usetikzlibrary{math}
    \usepackage{ifthen}

    \begin{document}
    \begin{tikzpicture}
    \tikzset{
    hexagram/.pic={
        \def\get##1/##2\null{\edef\set{##2}\definecolor{barcolor}{rgb}{##1}}
        \expandafter\get#1\null
      \foreach \d [count=\n] in \set{
        \ifthenelse{\d=0}
        {\draw [yshift=\n*2cm, line width=1cm, barcolor] (-6,0) -- (-1,0)  (1,0) -- (6,0);}
        {\draw [yshift=\n*2cm, line width=1cm, barcolor] (-6,0) -- (6,0);}
      }}
     }
    \foreach [count=\n] \m in {
      {1, 0, 0/0, 0, 0}, 
      {0, 1, 0/0, 0, 1}, 
      {0, 0, 1/1, 1, 1}}{
      \pic at (\n*15,0) {hexagram = \m};
    }
    \end{tikzpicture}
    \end{document} 

enter image description here

new edit

I wish a new version regarding the beloww comment would solve your issue.

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{math}
\usepackage{ifthen}

\begin{document}
\begin{tikzpicture}
\tikzset{
hexagram/.pic={
    \def\get##1/##2\null{\edef\set{##1,##2}%
    \definecolor{topcolor}{rgb}{##1}%
    \definecolor{bottomcolor}{rgb}{##2}%
    }
    \expandafter\get#1\null
  \foreach \d [count=\n] in \set{
    \ifthenelse{\d=0}
    {\draw [yshift=\n*2cm, line width=1cm, \ifnum\n>3 topcolor\else bottomcolor\fi] (-6,0) -- (-1,0)  (1,0) -- (6,0);}
    {\draw [yshift=\n*2cm, line width=1cm, \ifnum\n>3 topcolor\else bottomcolor\fi] (-6,0) -- (6,0);}
  }}
 }
\foreach [count=\n] \m in {
  {1, 0, 0/0, 0, 0}, 
  {0, 1, 0/0, 0, 1}, 
  {0, 0, 1/1, 1, 1}}{
  \pic at (\n*15,0) {hexagram = \m};
}
\end{tikzpicture}
\end{document}

enter image description here

P.S. As the paper color is white therefore the white color will be invisible! It would be better to fill the page with another color, e.g. gray.

javadr
  • 2,404
  • very close! I think I did not made myself clear. What I want is the first trigram in one color and second one in another, e.g. ䷊, the top 3 broken strokes in black [rgb(0,0,0) ] and bottom 3 in white [ rgb(1,1,1)]. – Tony Tan Jan 31 '19 at 01:33
  • 1
    @TonyTan I got it, see the new version of my response. – javadr Jan 31 '19 at 06:45