Plot 3d blocks in deep neural networks. Less code, better appearance and easier control.
- dnnplot
- Table of contents
- Load package
- Basic usage
- Available anchors
- Annotation
- Shift in z axis
- Alignment
- Plane block
- Grid block
- Options
- To be added...
- Thanks
- Download the package.
git clone https://github.com/ZhiyuanLck/dnnplot.git
-
Copy
dnnplot.sty
indnnplot/src/
to your root directory. -
Add the code below to the preamble.
\usepackage{dnnplot}
With dnnplot
, you are supposed to draw blocks from left to right, down to up and back to front, which are posit directions of x, y, and z axes respectively.
The block in dnnplot
is a customized shape, which means you can use it as a node with lots of anchors and all the styles that can be set for node. The grammar is simple:
\node[block={<specification>}];
where specification
is a list of keys/values
.
You can specify the length (or channels), width and height by block={x=<length>, y=<length>, z=<length>}
, where x, y, z
represent the length of edge that is paralleled to x, y, z axis respectively.
Here is a primary example (MWE):
\documentclass[tikz, border=4mm]{standalone}
\usepackage{dnnplot}
\begin{document}
\begin{tikzpicture}
\node[block={scale=1, x=30mm, y=30mm, z=30mm}, anchor=back south west] at (0, 0) {};
\draw[->, thick] (0, 0) -- (4, 0) node[below] {$x$};
\draw[->, thick] (0, 0) -- (0, 4) node[right] {$y$};
\draw[->, thick] (0, 0) -- (-2, -2) node[left] {$z$};
\end{tikzpicture}
\end{document}
We plot a base 3d block.
plot base block
A variety of anchors have been defined. They are all shown as below.
\documentclass[tikz, border=4mm]{standalone}
\usepackage{dnnplot}
\begin{document}
\begin{tikzpicture}
\newcommand{\frontanchors}{front, front north east, front north west, front south east, front south west}
\newcommand{\backanchors}{back, back north east, back north west, back south east, back south west}
\newcommand{\centeranchors}{center, north east, north west, south east, south west}
\tikzset{anchors/.style={fill=red, block={back plot, scale=1, x=5cm, y=5cm ,z=5cm}}}
\node[anchors] (a) {};
\foreach \a in \frontanchors{
\fill[fill=red] (a.\a) circle (2pt) node[below] {\a};
}
\foreach \a in \centeranchors{
\fill[fill=blue] (a.\a) circle (2pt) node[below] {\a};
}
\foreach \a in \backanchors{
\fill[fill=green] (a.\a) circle (2pt) node[below] {\a};
}
\end{tikzpicture}
\end{document}
anchors
I define a command to annotate easily:
\blocklabel[<optional style>]{<node name>}{<edge specification>}{<text>}
-
<node name>
: specified when you declare a node such as\node (a) {};
then thenode name
isa
. -
<edge specification>
: specify the edge to which the label are attached. Availableedge specifications
such asupperright
are shown in the figure below. If you pass a undefined specification, nothing will happen. -
<text>
: text to be shown in the node. -
<optional style>
: all the arguments are passed to the text node. If it is empty, default position of the label are set. Options likenear start
also work.
Note: no semicolon is needed in this command!
\documentclass[tikz, border=4mm]{standalone}
\usepackage{dnnplot}
\begin{document}
\begin{tikzpicture}
\tikzset{labels/.style={fill=red, block={back plot, scale=1, x=5cm, y=5cm ,z=5cm}}}
\node[labels] (a) {};
\foreach \l in {fronteast, frontwest, frontnorth, frontsouth, backeast,
backwest, backnorth, backsouth, upperleft, upperright, lowerleft, lowerright}
{\blocklabel[font=\itshape]{a}{\l}{\l~label}}
\end{tikzpicture}
\end{document}
annotation
- You can use
block={zshift=<distance>}
to apply a shift in z axis.
\documentclass[tikz, border=4mm]{standalone}
\usepackage{dnnplot}
\begin{document}
\begin{tikzpicture}
\tikzset{A/.style={block={back plot, scale=1, x=5cm, y=5cm ,z=5cm, #1}}}
\draw[->, thick] (0, 0) -- (6, 0) node[below] {$x$};
\draw[->, thick] (0, 0) -- (0, 6) node[right] {$y$};
\draw[->, thick] (0, 0) -- (-3.5, -3.5) node[left] {$z$};
\node[A, fill=red, anchor=back south west] (a) at (0, 0) {};
\node[fill=green, A={zshift=2.5cm}] at (a) {}; % shift half of width in z axis
\end{tikzpicture}
\end{document}
shift in z axis
- Tikz library
positioning
only supports shifting in 2d space. Withdnnplot
you can useblock={pre=<node name>, front=<distance>}
to carry out the function just likeright=2cm of a
inpositioning
.
\documentclass[tikz, border=4mm]{standalone}
\usepackage{dnnplot}
\begin{document}
\begin{tikzpicture}
\tikzset{
base/.style n args={4}{
block={scale=1, x=#1mm, y=#2mm, z=#3mm, #4}
},
A/.style={fill=red, base={20}{20}{50}{#1}},
B/.style={fill=blue, base={20}{20}{20}{#1}},
}
\node[A] (a) {};
\node[B={pre=a, front=0mm}] (b) {};
\node at (a.north) {A};
\node at (b.north) {B};
\end{tikzpicture}
\end{document}
front of a block
You can apply arbitrary alignment with the option block={pre=<node name>, align axis=<axis>, hfactor=<value>, vfactor=<value>}
. By default, center alignment is applied.
block={align axis=<axis>}
,align axis
is set tox
by default.
align axis=x
: you are going to apply the alignment in the way that you are looking at the referenced block from right to left, and then you wish to align current block among left edge, right edge, ... etc. or just let the block to be center aligned.align axis=y
: you are going to apply the alignment in the way that you are looking at the referenced block from top to bottom.align axis=z
: you are going to apply the alignment in the way that you are looking at the referenced block from front to back.
how does alignment work
Figure above shows how the alignment works. The code is in `examples/dnnplot_align_axis.tex`.hfactor=<value>
andvfactor=<value>
- Understanding the effect of these two parameters, you are supposed to learn something about how does the alignment work in
dnnplot
:- First, direction of the view is set by e. g.
align axis=x
, which means you look at y-z plane from right to left. Suppose the rectangle D is obtained by shifting the right side of the referenced block so that it passes through the center of current block. Initially, we fix the center current block at the lower left corner of D, wherehfactor=0, vfactor=0
. - Then, horizon shift and vertical shift are carried out. If the block are wished to be horizontally shifted to the lower right corner of D, corresponding
hfactor
should be set to1
. Same asvfactor
if you want to shift the block vertically to the upper left corner. We can definehshift
(not a option) to be the shift distance from the lower left corner to lower right corner andvshift
is similarly defined. - The eventual effect is that you settle the block in the lower left corner, and shift the block
hfactor*hshift
horizontally andvfactor*vshift
vertically. It is just like normalized coordinates. Of cause, you can set the value of factor out of[0, 1]
, then the block will be shifted out of the border of D.
- First, direction of the view is set by e. g.
Now we can plot some fancy blocks like this:
\documentclass[tikz, border=4mm]{standalone}
\usepackage{xcolor}
\usetikzlibrary{positioning}
\usepackage{dnnplot}
\begin{document}
\begin{tikzpicture}
\tikzset{
base/.style n args={4}{
block={scale=1, x=#1mm, y=#2mm, z=#3mm, #4}
},
A/.style={fill=red, base={200}{10}{200}{#1}},
B/.style 2 args={},
B/.code 2 args={
\pgfmathsetmacro\tempa{100*#1}
\pgfmathsetmacro\tempb{100*#2}
\pgfkeysalso{
above=2cm of a, fill=red!\tempa!green!\tempb!blue,
base={10}{10}{10}{align axis=y, hfactor=#1, vfactor=#2, pre=a},
fill opacity=0.5,
}
}
}
\node[A] (a) {};
\foreach \h in {0, 0.1, ..., 1.1}{
\foreach \v in {0, 0.1, ..., 1.1}{
\node[B={\h}{\v}] {};
}
}
\end{tikzpicture}
\end{document}
fancy blocks
You can quickly apply alignment of common styles quickly by the way like this:
block={pre=<node name>, align axis=<axis>, align=<align specification}
-
<node name>
: name of the defined node. -
<axis>
: apply the alignment among<axis>
. -
<align specification>
: specify the style of the alignment. Now it supportscenter, left, right, up, down, upperleft, upperright, lowerleft, lowerright
. Actually, if you pass other undefined<node name>
or<align specification>
, it is just like passingcenter
.Note:
<align specification>
has higher priority! If you have set<align specification>
, setting ofhfactor
andvfactor
will be ignored.
\documentclass[tikz, border=4mm]{standalone}
\usetikzlibrary{positioning, calc}
\usepackage{dnnplot}
\begin{document}
\begin{tikzpicture}[font=\large\bfseries, line width=1pt]
\tikzset{
base/.style n args={4}{
block={scale=0.5, x=#1mm, y=#2mm, z=#3mm, #4}
},
A/.style={fill=red, base={10}{80}{150}{#1}},
B/.style={fill=teal,right=1cm of a, base={10}{20}{30}{#1}},
}
\node[A] (a) {};
\foreach \a [count=\i] in {center, left, right, up, down, upperleft, upperright, lowerleft, lowerright}{
\node[B={pre=a, align=\a}] (\i) {};
\draw[->] let \p\i=(\i.east) in (\i.east) -- (4cm, \y\i) node[right] {\a};
}
\end{tikzpicture}
\end{document}
alignment
What will happen if you set align axis=y
, but shift the block among x axis? Here is a example.
\documentclass[tikz, border=4mm]{standalone}
\usetikzlibrary{positioning}
\usepackage{dnnplot}
\usepackage{amsmath, bm}
\begin{document}
\begin{tikzpicture}[font=\large\bfseries, line width=1pt]
\tikzset{
base/.style n args={4}{
block={scale=0.5, x=#1mm, y=#2mm, z=#3mm, #4}
},
A/.style={fill=red, base={50}{80}{150}{#1}},
B/.style={base={10}{20}{30}{#1}},
}
\node[A, anchor=front south west] (a) at (0, 0) {};
\foreach \axis/\color/\d in {x/teal/3.5cm, y/cyan/8cm, z/orange/13cm}{
\begin{scope}[local bounding box=box-\axis]
\foreach \align [count=\i] in {center, left, right, up, down, upperleft, upperright, lowerleft, lowerright}{
\node[B={pre=a, align axis=\axis, align=\align}, fill=\color, right=\d of a] {};
}
\end{scope}
\node at (0, -1 -| box-\axis) {align axis=$\bm{\axis}$};
}
\end{tikzpicture}
\end{document}
alignment among different axis
All the alignment options should set block={pre=<node name>}
first. Otherwise, nothing will happen!
If you want a plane block in x-y plane, letting z=0cm
(which is default so you can just ignore this option) seems to be a feasible way, but it may cause some little problem such as some lines are drawn a little wider. So, you'd better add the block={plane}
option to avoid the case.
Set block={grid={(<xnum>, <ynum>, <znum>)}}
to draw a grid block. You can combine back plot
option with grid
option to draw hidden lines. <xnum>, <ynum>, <znum>
are the number of blocks in the direction of x, y, z
axis.
All anchors sitting on grid points are available by their names like a+y-2-1
, where +
represents we select the plane which has a greater y coordinate
, y
represents x-z
plane and -2-2
represents coordinate on x-z
plane.
Here is an example:
\documentclass[tikz, border=4mm]{standalone}
\usepackage{dnnplot}
\usetikzlibrary{arrows.meta}
\tikzset{
A/.style={
block={scale=2, x=4cm, y=3cm, z=3cm, grid={(4,3,3)}, back plot},
},
B/.style={fill=violet},
C/.style={fill=orange},
}
\begin{document}
\begin{tikzpicture}
\node[A, fill=teal, anchor=back south west] (a) at (0, 0) {};
\begin{scope}[->, thick]
\draw (0, 0) -- (9, 0) node[below] {$x$};
\draw (0, 0) -- (0, 7) node[right] {$y$};
\draw (0, 0) -- (-3.5, -3.5) node[left] {$z$};
\end{scope}
\foreach \x in {x, y, z}{
\draw[red, -Stealth, thick] (a-\x-2-1) -- (a+\x-2-1);
}
\foreach \s/\o in {B/+, C/-}{
\foreach \x in {x, y, z}{
\fill[\s] (a\o\x-2-1) node[below right, font=\bfseries] {a\o\x-2-1} circle (2pt);
}
}
\end{tikzpicture}
\end{document}
grid block
x
: default 0cm.y
: default 0cm.z
: default 0cm.scale
: apply a scaling to the block, default 0.5.pre
: name of the previous node, used for shifting and alignment.align axis
: axis to be aligned among.hfactor
: coefficient ofhshift
.vfactor
: coefficient ofvshift
.align
: quick style of alignment.back plot
: draw hidden edges as dashed lines.plane
: draw plane block, i. e. 3d rectangle.grid
: draw a grid block, default{(1, 1, 1)}
.
Some options of node are set by default. If you want to overload them, please add the option after block={...}
in node[block={...}]
.
inner sep=0
draw
fill opacity=.3
line width=.2pt
- more shape (or you can pull a request)
Schrödinger's cat helps me a lot and provides some good ideas.