This answer uses
- the
matrix
library for the main part, including some auxiliary macros \rd
and \rn
for some random content in the matrix,
- the
calc
library for some easy vector calculation,
- my
paths.ortho
library (code: [1] and [2]) for the connections outside of the matrix,
- my
positioning-plus
library for the use of left=of |(n1)(n2)
which positions a node to the left of the vertical center of (n1)
and (n2)
.
The local cs
key (packaged later in the my cs
style) is used to create a custom coordinate system that slants the vertical axis for the three-dimension part of the cube. (There are a lot of different ways to achieve this.)
There are also various different ways to achieve specific things in this code:
We could have drawn the lines inside the matrix as part of the inner nodes that lie inside it. We could have used the workarounds in the linked answer to replace my library.
A few explanations:
tight matrix
I have used a style tight matrix
defined as
tight matrix/.style={
matrix of nodes, inner sep=+0pt, outer sep=+0pt,
every cell/.append style={
every node/.append style={
outer sep=+0pt,
inner xsep=+.1em,
inner ysep=+.3333em, % default (overwritten by matrix inner sep)
align=center,
text depth=+0pt, % depth("y"),
text height=height("M"),
text width=width("MMM-00-00"), % possibly other approaches
}}},
that sets up a tight matrix where the matrix’ nodes are set border to border. The text …
keys are used so that all nodes have same height, depth and width.
The matrix is then filled just as you would.
A custom coordinate system simulating the third dimension
With my cs/.style={local cs={m.north west}{m.north east}{1}{2}}
I'm setting up a coordinate system which origins lie at (m.north west)
, the x
vector points to (m.north east)
and the y coordinate is “x-slanted” by the factor of 1
(For every y you go an additionally 1
to the right.) Also, the y
is doubled.
I have used the xslant
ing as a way to use orthogonal parts (like |-
, -|
or my own -|-
) without the need to worry about the third dimension.
However, there is actually a third dimension in TikZ. Its vector can be set with the z
key and its default is (-3.85mm, -3.85mm)
. (So it actually points “out” of the paper.) We cannot use this third dimension in path operators. (It’s just a coordinate specification which maps three values to 2d-vectors.) However the direction of the y
vector can be calculated from the xslant
ing: <direction> = atan(1/<xslant>)
.
The “third” dimension
With the coordinate system set up, we can draw the cube’s borderuse a usual rectangle
path operator and it will draw a slanted rectangle.
The coordinate system also allows us to use the relative coordinate + (up:1)
if we want to get into the third dimension anyway.
Lines
With the custom coordinate system set up we can draw the box’s border:
\draw (0,0) |- (1,1) -- (right:1)
(m.south east) -- ++ (up:1) -- (1,1);
In a few loops, we draw the lines:
\foreach \c in {1,2,3}
\draw (m-12-\c.south east) -- (m-1-\c.north east) -- ++ (up:1);
\foreach \c in {1,...,12}
\draw[if={isodd(\c)}{densely dashed}{}]
(m-\c-1.south west) -- (m-\c-4.south east) -- ++(up:1);
\foreach \c in {1,...,7}
\draw[if={isodd(\c)}{densely dashed}{}]
(up:\c/8) coordinate (tl-\c) -- ++ (right:1) -- ([shift=(up:\c/8)]m.south east);
Here, I also define seven coordinates we later use to place the nodes at the t
op l
eft of the cube.
Even though, in all three paths, the custom coordinate system is active, named nodes/coordinates are not affected as they are referenced absolutely. The ++(up:1)
is used to get into the third dimension. The same applies to the shift coordinate at the end.
Nodes
For the placing of the descriptive nodes we either use the matrix’ cells’ nodes’ anchors as in
\foreach \st/\lt[count=\c from 0, evaluate={\d=int(2*\c+1)}]
in {af/Africa, as/Asia, au/Australia, eu/Europe, na/North\\America, sa/South\\America}
\node[continent] (\st) at (m-\d-1.south west) {\lt};
or the previous defined coordinates:
\foreach \st[count=\c from 0, evaluate={\d=int(2*\c+1)}] in {air, sea, road, rail}
\node[continent, left=of (tl-\d)](\st){\st};
The positioning-plus
library allows us to do left=of |(<n1>)(<n2>)
which place the new node to the left of a coordinate that lies in the middle of the most left vertical line that spans the nodes (<n1>)
and (<n1>)
. We could also write left=of ($(<n1>.north west)$!.5!(<n2>.south west)$)
with just basic positioning
.
The lines are drawn with the -|-
to path and active my cs
(see the options of \begin{scope}
). The xslant
ing also slants the orthogonal connections:
\node[hemi, left=of |(af)(eu)] (eh) {Eastern\\Hemisphere}
(eh) \foreach \co in {af, as, au, eu}{ edge[-|-, hvvh/distance=.3cm] (\co)};
Without paths.ortho
you can write:
\node[hemi, left=of |(af)(eu)] (eh) {Eastern\\Hemisphere}
(eh.east) \foreach \co in {af, as, au, eu}{
edge[to path=++(right:.3cm) -| (\tikztotarget)] (\co)};
Code
\documentclass[tikz]{standalone}
\usetikzlibrary{matrix,paths.ortho,calc,positioning-plus}
\newcommand*\rd{{% random date
\pgfmathrandominteger\m{0}{11}\ifcase\m Jan\or Feb\or Mar\or Apr\or May\or
Jun\or Jul\or Aug\or Sep\or Oct\or Nov\or Dec\fi
-\pgfmathprint{random(31)}-\pgfmathprint{random(100)}}}
\newcommand*\rn{\pgfmathprint{random(100,9999)}}
\tikzset{if/.code n args=3{\pgfmathparse{#1}\ifnum\pgfmathresult=0
\pgfkeysalso{#3}\else\pgfkeysalso{#2}\fi}}
\tikzset{local cs/.style n args=4{shift={(#1)}, x=($(#2)-(#1)$), xslant={#3}, yscale={#4}}}
\begin{document}\sffamily
\begin{tikzpicture}[
tight matrix/.style={
matrix of nodes, inner sep=+0pt, outer sep=+0pt,
every cell/.append style={
every node/.append style={
outer sep=+0pt,
inner xsep=+.1em,
inner ysep=+.3333em, % default (overwritten by matrix inner sep)
align=center,
text depth=+0pt, % depth("y"),
text height=height("M"),
text width=width("MMM-00-00"), % possibly other approaches
}}},
desc/.style={/utils/exec=\scriptsize}, % font key is not perfect
continent/.style={
desc, align=center, anchor=east},
hemi/.style={desc, align=center, text width=width("Hemisphere")},
route/.style={desc},
Route/.style={font=\bfseries},
]
% The matrix
\matrix[tight matrix, draw] (m) {
190 & 215 & 160 & 240 \\
Feb-17-99 & Apr-22-99 & Sep-07-99 & Dec-01-99 \\
\rn & \rn & \rn & \rn \\
\rd & \rd & \rd & \rd \\
\rn & \rn & \rn & \rn \\
\rd & \rd & \rd & \rd \\
\rn & \rn & \rn & \rn \\
\rd & \rd & \rd & \rd \\
\rn & \rn & \rn & \rn \\
\rd & \rd & \rd & \rd \\
\rn & \rn & \rn & \rn \\
\rd & \rd & \rd & \rd \\
};
% The 3D
\tikzset{my cs/.style={local cs={m.north west}{m.north east}{1}{2}}}
\begin{scope}[my cs]
\draw (0,0) |- (1,1) -- (right:1)
(m.south east) -- ++ (up:1) -- (1,1);
% The lines
\foreach \c in {1,2,3}
\draw (m-12-\c.south east) -- (m-1-\c.north east) -- ++ (up:1);
\foreach \c in {1,...,12}
\draw[if={isodd(\c)}{densely dashed}{}]
(m-\c-1.south west) -- (m-\c-4.south east) -- ++(up:1);
\foreach \c in {1,...,7}
\draw[if={isodd(\c)}{densely dashed}{}]
(up:\c/8) coordinate (tl-\c) -- ++ (right:1) -- ([shift=(up:\c/8)]m.south east);
\end{scope}
% The Descriptions
\foreach \st/\lt[count=\c from 0, evaluate={\d=int(2*\c+1)}]
in {af/Africa, as/Asia, au/Australia, eu/Europe, na/North\\America, sa/South\\America}
\node[continent] (\st) at (m-\d-1.south west) {\lt};
\node[hemi, left=of |(af)(eu)] (eh) {Eastern\\Hemisphere}
(eh) \foreach \co in {af, as, au, eu}{ edge[-|-, hvvh/distance=.3cm] (\co)};
\node[hemi] at (eh|-m-11-1.north) (wh) {Western\\Hemisphere}
(wh) \foreach \co in {na, sa}{ edge[-|-, hvvh/distance=.3cm] (\co)};
\begin{scope}[node distance=.25cm, hvvh/distance=.2cm, my cs]
\foreach \st[count=\c from 0, evaluate={\d=int(2*\c+1)}] in {air, sea, road, rail}
\node[continent, left=of tl-\d](\st){\st};
\node[route, left=of |(sea)(air)] (ng) {non-ground}
(ng) \foreach \co in {sea, air}{ edge[-|-] (\co)};
\node[route, left=of |(rail)(road)] (g) {ground}
(g) \foreach \co in {rail, road}{ edge[-|-] (\co)};
\node[Route, left=of |(g)(ng)] (R) {Route}
(R) \foreach \co in {g, ng}{ edge[-|-] (\co)};
\end{scope}
\end{tikzpicture}
\end{document}
Output

pstricks
etc.) but not if you know nothing about the system and have a 2 hour limit. If this is a one-off, use a graphical programme. If you need to draw other cubes or things, it might be worth more than 2 hours to learn a system.