6

Would it be possible to control a matrix in Tikz as accurately as possible as with regular shapes?

For example, inside a Tikzpicture, I could simply control a shape's size by writing

\filldraw[fill=white] (6, 2) rectangle (8, 1) node[]{};

where the numbers represent respectively the left, top, right and bottom side of the rectangle. This way I can control how "tall" or long the rectangle is.

I can't do the same with the matrix, as it only works using the syntax:

\node[] at (x, y)

However this is rather not precise as I'd like to be able to set the actual coordinates. What can I do? I have looked at the Tikz manual and on this site (and on the internet) but couldn't find anything.

Here is the example of what I have and what I want:

enter image description here

and here is the code:

\documentclass[10pt]{article}
\usepackage[a4paper, margin=1cm]{geometry}
\usepackage[utf8]{inputenc}
\usepackage{rotating}
\usepackage{amsmath}
\usepackage{pgfplots}
\usepackage{tikz}

\usetikzlibrary{arrows,backgrounds,snakes,shapes,shapes.multipart,positioning}
\pgfplotsset{compat=1.7}
\pagestyle{empty}

\begin{document}

    \tikzstyle{typnode} = [midway, align=center, inner sep=0pt]
    \tikzstyle{data} = [font=\scriptsize, inner sep=0pt, rotate=90, minimum size=0pt,text width=0.5cm]

    \begin{tikzpicture}[x=6.4mm,y=5mm]
            \centering 
       \draw[|->, -latex, draw] (0,0) -- (15,0);
       \draw[-, dashed] (-0.5,0) -- (0,0);

     \foreach \x [evaluate=\x as \xear using int(1600+\x*10)] in {0,1,...,15}{ 
            \draw[-] (\x,0) node[below=7pt,anchor=east,xshift=0,rotate=45,font=\footnotesize] {$\xear$}; 
            \draw[] (\x,-0.2) -- (\x,0.2);
            \draw[] (\x+.5,0) -- (\x+.5,0.1);
    }

    \filldraw[fill=white] (6, 1.5) rectangle (13.1, 0.5) node[typnode]{...to here (1660-1731)};
    \matrix[draw, fill=white] {\node[data]{1660}; & \node[text width=3cm,typnode]{from here...}; & \node[data]{1731};\\};

   \end{tikzpicture}
\end{document}

Please note that I'm not concerned about the height of the node. The thing I really want to set are the left and right side so that the matrix fits the length denoted by the dates.

Alenanno
  • 37,338
  • Can you post an MWE of what you have tried so far? It can give us a clearer picture of what you are trying to do. – hpesoj626 Mar 30 '13 at 23:52
  • @hpesoj626 I usually provide it, however I don't really have an error or warning, the shape comes exactly as I want it, I just don't know how to transform it... I didn't think it was particularly necessary this time, but I'll try to come up with something for the sake of the question. :) – Alenanno Mar 30 '13 at 23:53
  • I don't see the problem actually: you can insert a matrix by using math mode in a node. If you want to draw arrows and stuff like that, you can define an additional node with the fit package that overlays the old (matrix node). – willeM_ Van Onsem Mar 30 '13 at 23:57
  • @Alenanno It's perfectly fine to provide a MWE. Solvers can use it to make suggestions directly from the given code. It doesn't have to be always something which contains an error. That is why it is called minimal working example (MWE) :) – hpesoj626 Mar 31 '13 at 00:01
  • @hpesoj626 I was aware of the meaning of MWE but thanks anyway. :D Added along with an example of what I want (the code typesets that). – Alenanno Mar 31 '13 at 00:04
  • @CommuSoft Care to elaborate on that? I have added a MWE (in case you need it). :) – Alenanno Mar 31 '13 at 00:05
  • Can't you just define a coordinate above 1660 (with coordinate manipulation), then rotate the text 90 degrees on that, do the same with 1731, calculate the coordinate in the middle, create a node with a label. Define a node that fits all three of them and let that node draw a rectangle? – willeM_ Van Onsem Mar 31 '13 at 00:07
  • Could you reduce the MWE so that it contains only the matrices and specify the matrix’ dimensions as you want them? Is this related to tikz: Can we set the corner coordinates of a rectangle? (By the way, no, you can not control a shape’s size with (a,b) rectangle (c,d) node[]{}: The node is just a node on the rectangle’s path where the middle position is set to the middle of the rectangle, it has no relation to the rectangle. If the node’s content is wider than the rectangle it will protrude the rectangle’s lines. Add draw to the node’s options …) – Qrrbrbirlbel Mar 31 '13 at 00:17
  • @Qrrbrbirlbel There is only one matrix. It should replace the other shape I've included in it (not the height, just the length). I want to move it there. However I've spotted some info that is not necessary for the question... :P – Alenanno Mar 31 '13 at 00:19
  • What information should the matrix contain? Should the information (or parts of it) be synchronized with the timeline below? – Gonzalo Medina Mar 31 '13 at 00:23
  • @Alenanno Sorry, now I get what you meant with from here and to here, I’m slow today. What should happen if the contains of the matrix is wider than the the space betwee 1660 and 1731. What is your typical content of the matrix? Do you actually need the matrix or do they only consist of three elements (the start (1660), the end (1731) and some text in between? – Qrrbrbirlbel Mar 31 '13 at 00:24
  • @Qrrbrbirlbel Oh no problem! :D Maybe it wasn't as clear as I thought. If it's longer then I prefer to expand on height. The dates represent actual dates and that length represents a lifespan of a person (born in 1660 and dead in 1731) so I can't exceed those dates. However I don't mind expanding on height (but I doubt it's going to happen, I only need to post a name and some small shapes (which you can't see here but they do fit in). :D – Alenanno Mar 31 '13 at 01:06
  • @GonzaloMedina See my last comment here for a quick explanation of the graph. In short, yes. :D – Alenanno Mar 31 '13 at 09:56

2 Answers2

6

Here is a matrix-less approach.

And a macro …

Code

\documentclass[tikz,convert=true]{standalone}
\usepackage{tikz}
\usetikzlibrary{arrows,positioning}
\tikzset{
    typnode/.style={midway, align=center, inner sep=0pt},
    data/.style={font=\scriptsize, inner sep=1pt, rotate=90, minimum size=0pt},
    datastart/.style={below right, data, xshift=5},
    dataend/.style={above right, data, xshift=5},
    level/.style={
        yshift = #1*.8cm
    },
    level/.initial=0,
}

\newcommand*{\fakematrix}[4][]{
    \begin{scope}[#1]
    \node[datastart] (d1-start) at ({(#2-1600)/10},0) {#2};
    \node[dataend]   (d1-end)   at ({(#3-1600)/10},0) {#3};
    \draw (d1-start.north east) rectangle (d1-end.south west) node [typnode] {#4};
    \end{scope}
}
\begin{document}
\begin{tikzpicture}[x=6.4mm,y=5mm]
\draw[|->, -latex, draw] (0,0) -- (15,0);
\draw[-, dashed] (-0.5,0) -- (0,0);

\foreach \x [evaluate=\x as \xear using int(1600+\x*10)] in {0,1,...,15}{ 
    \draw (\x,0) node[below=7pt,anchor=east,xshift=0,rotate=45,font=\footnotesize] {$\xear$}; 
    \draw (\x,-0.2) -- (\x,0.2);
    \draw (\x+.5,0) -- (\x+.5,0.1);
}

\fakematrix{1660}{1731}{Daniel Defoe}% produces the same like above
\fakematrix{1600}{1655}{Edward Doty}
\fakematrix[typnode/.append style={font=\tiny}]{1735}{1750}{Eh?}
\fakematrix[level=1]{1601}{1700}{The 17th century.}
\end{tikzpicture}
\end{document}

Output

enter image description here

Qrrbrbirlbel
  • 119,821
  • Thanks, I can't follow up at the moment but I'll give you feedback as soon as possible. :) – Alenanno Mar 31 '13 at 01:08
  • Sorry for the late feedback... I was wondering, is it possible to set one more parameter which is the Y position? I mean, say if I want to set one more on top of each other (speaking 2D here)... – Alenanno Apr 01 '13 at 16:29
  • Ah one more thing: I've tried customizing that datastart/.style={below right, data, xshift=5} to include a font=\scriptsize but the dates stay as big as the text. Sorry for the hassle. I think however that apart from these two things I've asked in the comments, yours is the best solution for me. :) – Alenanno Apr 01 '13 at 16:37
  • @Alenanno If you find Qrrbrbirlbel's answer the best solution, you can accept it by clicking on the tick mark. – hpesoj626 Apr 02 '13 at 09:56
  • @hpesoj626 Your solution and Qrrbrbirlbel's solutions are quite similar but they both work with a fixed Y position. I wanted to make that a variable as I have different lives to represent. But as I mentioned, I don't know how to add that, any attempt I make leads to errors. – Alenanno Apr 02 '13 at 10:03
6

Here are two alternative solutions. The first one is through the use of matrix, as you have been attempting.

Solution using matrix

enter image description here

You can try to use shift's to make it look more accurate. Here is the code.

\documentclass[10pt,border=5]{standalone}
%\usepackage[a4paper, margin=1cm]{geometry}
\usepackage[utf8]{inputenc}
\usepackage{rotating}
\usepackage{amsmath}
\usepackage{pgfplots}
%\usepackage{tikz}

\usetikzlibrary{arrows,backgrounds,snakes,shapes,shapes.multipart,positioning}
\pgfplotsset{compat=1.7}
\pagestyle{empty}

\begin{document}

\tikzset{
    typnode/.style={midway, align=center, inner sep=0pt},
    data/.style={font=\scriptsize, inner sep=1pt, anchor=center, rotate=90, minimum size=0pt},
}
    \begin{tikzpicture}[x=6.4mm,y=5mm]
            \centering 
       \draw[|->, -latex, draw] (0,0) -- (15,0);
       \draw[-, dashed] (-0.5,0) -- (0,0);

     \foreach \x [evaluate=\x as \xear using int(1600+\x*10)] in {0,1,...,15}{ 
            \draw[-] (\x,0) node[below=7pt,anchor=east,xshift=0,rotate=45,font=\footnotesize] {$\xear$}; 
            \draw[] (\x,-0.2) -- (\x,0.2);
            \draw[] (\x+.5,0) -- (\x+.5,0.1);
    }

    \matrix[draw, fill=white, anchor=west] at (6,1.5) {%
            \node[data]{1660}; 
                & \node[text width=110.9, typnode]{%
                Explanations...and some more explanations}; 
                & \node[data]{1731};\\
            };

   \end{tikzpicture}
\end{document}

Solution using the fit library

enter image description here

\documentclass[10pt,border=5]{standalone}
%\usepackage[a4paper, margin=1cm]{geometry}
\usepackage[utf8]{inputenc}
\usepackage{rotating}
\usepackage{amsmath}
\usepackage{pgfplots}
%\usepackage{tikz}

\usetikzlibrary{fit,positioning}
\pgfplotsset{compat=1.7}
\pagestyle{empty}

\begin{document}
\tikzset{
    typnode/.style={midway, align=center, inner sep=0pt},
    data/.style={font=\scriptsize, inner sep=0pt, rotate=90, minimum size=0pt, align=center},
}
    \begin{tikzpicture}[x=6.4mm,y=5mm]
            \centering 
       \draw[|->, -latex, draw] (0,0) -- (15,0);
       \draw[-, dashed] (-0.5,0) -- (0,0);

     \foreach \x [evaluate=\x as \xear using int(1600+\x*10)] in {0,1,...,15}{ 
            \draw[-] (\x,0) node[below=7pt,anchor=east,xshift=0,rotate=45,font=\footnotesize] {$\xear$}; 
            \draw[] (\x,-0.2) -- (\x,0.2);
            \draw[] (\x+.5,0) -- (\x+.5,0.1);
    }

        \node [data, yshift=-2.75, anchor=center] (start) at (6,1) {1660};
        \node [data, yshift=3,anchor=center] (end) at (13.1,1) {1731};

        \node [fit=(start)(end), draw, align = center, inner sep=0.5pt,label=center:Explanations] {};
%    \matrix[draw, fill=white, anchor=west] at (6,1.5) {\node[data]{1660}; & \node[text width=110.9, typnode]{Explanations...and some more explanations}; & \node[data]{1731};\\};

   \end{tikzpicture}
\end{document}

Update

I have created a macro called \yourmatrix that takes four arguments. The first argument is the start year, the second the end year, the third as the y position, and the fourth as the text/explanations.

Note that the matrix, looking at it now, is not optimal. The disadvantage is that it is hard to control the actual text width as the matrix has some padding. Introducing inner sep=0pt also gives unpredictable results. You can see the problem when with

\yourmatrix{1610}{1650}{Some more!}

enter image description here

Here is the code that you can play with.

\documentclass[10pt,border=5]{standalone}
%\usepackage[a4paper, margin=1cm]{geometry}
\usepackage[utf8]{inputenc}
%\usepackage{rotating}
%\usepackage{amsmath}
%\usepackage{pgfplots}
\usepackage{tikz}

\usetikzlibrary{arrows,backgrounds,decorations,shapes,shapes.multipart,positioning}
%\pgfplotsset{compat=1.7}
%\pagestyle{empty}


\begin{document}
\tikzset{
    typnode/.style={midway, align=center},
    data/.style={font=\scriptsize, anchor=center, rotate=90, minimum size=0pt},
}

\newcommand{\yourmatrix}[4]{
    \pgfmathsetmacro{\lifespan}{(#2-#1)/0.64}
    \matrix[ampersand replacement=\&, inner sep=0.5pt, column sep=1mm,fill=white, draw, matrix anchor=west, anchor=west] at ({(#1-1600)/10},{#3}) {%
            \node[data]{#1};
                \& \node[text width=\lifespan, typnode]{%
                #4}; 
                \& \node[data,below]{#2};\\
            };
}

    \begin{tikzpicture}[x=6.4mm,y=5mm]
       \draw[|->, -latex, draw] (0,0) -- (15,0);
       \draw[-, dashed] (-0.5,0) -- (0,0);

     \foreach \x [evaluate=\x as \xear using int(1600+\x*10)] in {0,1,...,15}{ 
            \draw[-] (\x,0) node[below=7pt,anchor=east,xshift=0,rotate=45,font=\footnotesize] {$\xear$}; 
            \draw[] (\x,-0.2) -- (\x,0.2);
            \draw[] (\x+.5,0) -- (\x+.5,0.1);
    }

        \yourmatrix{1660}{1731}{1.5}{Here is the explanation}
        \yourmatrix{1610}{1650}{2}{Some more!}
   \end{tikzpicture}
\end{document}

Let me just explain the arithmetic involved with

\pgfmathsetmacro{\lifespan}{(#2-#1)/0.64}

The divisor 0.64 came from the fact that you have set x=6.4mm and each unit is labeled with increments of 10. Since 1 cm = 10 mm, each unit is then to be multiplied by a factor of 100. The part (#2-#1) gets the difference between year start and year end, and so gets the life span (\lifespan) in terms of years.

I don't know if this method has some fix but at the moment it is eluding me.

Moriambar
  • 11,466
hpesoj626
  • 17,282
  • I've just had an insane idea... Well, let's hope it's not insane. :D I was wondering, for the Matrix solution, what if you set the text width in the matrix (not the nodes inside) to be as much points as they are for the actual lifespan? For example, from 1660 to 1731 they are 71 years. Can I set Tikz to use a new length so that 1 point equals one year in my graph, so that if I write text width=71length it spans for "71 years"? If this would be easily implemented then I'd use your matrix-related solution. :) – Alenanno Mar 31 '13 at 13:26
  • Perhaps one way is to use \pgfmathsetmacro{\lifelength}{71} \pgfmathsetmacro{\lifespan}{\lifelength/6.4*10} then use text width=\lifespan in the node option. – hpesoj626 Apr 01 '13 at 04:53
  • Sorry if I'm pestering you but I've been trying all morning for this but... How do you fix that macro to be applicable per case? I've meant to use "#1"... The problem is that I don't know how to calculate the length of "one year" or even one unit length so that I can tell Latex "stretch this by X points" or whatever. – Alenanno Apr 01 '13 at 11:24
  • @Alenanno It's okay. But I am afraid I can't provide a better solution. See my edit. – hpesoj626 Apr 02 '13 at 09:35
  • Thanks for your help and time, I'll take a look at it. :) – Alenanno Apr 02 '13 at 09:39
  • 1
    BTW, snakes library is now deprecated by decorations library for version 2.10. :) – hpesoj626 Apr 02 '13 at 09:41
  • Ah, thanks for the heads up. One thing: can I set also the "height", i.e Y position? I'd try to add the variable myself but I am a newbie at making new commands. :D – Alenanno Apr 02 '13 at 09:43
  • In the codes above, you can replace 1.5 with your desired value. – hpesoj626 Apr 02 '13 at 09:58