11

Inspired by How to create nice-looking nuclei in TikZ?, I am trying to draw arrangements of spheres, in particular the sphere packing in a sphere problem.

From Wikipedia - "Sphere packing in a sphere is a three-dimensional packing problem with the objective of packing a given number of equal spheres inside a unit sphere. It is the three-dimensional equivalent of the circle packing in a circle problem in two dimensions."

For small numbers, the results are trivial:

enter image description hereenter image description hereenter image description here

But here are some larger examples which are more complicated:

enter image description hereenter image description here

These images were taken from the Wikipedia article linked above.

My question is how could one go about creating such diagrams using TikZ? Using the tikz-3dplot package springs to mind. But one tricky aspect is you have to draw the balls in the right order, so they overlap correctly to give the desired 3D view.

My first attempt at drawing the trivial cases:

enter image description here

MWE

\documentclass[margin=0.5cm]{standalone}
\usepackage{tikz}
\usepackage{tikz-3dplot}
\begin{document}
\tdplotsetmaincoords{30}{120}
\begin{tikzpicture}[tdplot_main_coords]

\shade [ball color=red] (0,0,0) circle (1cm);

\begin{scope}[xshift=4cm]
\draw [gray] (0,0,0) circle (1cm);
\shade [ball color=red] (0:0.5) circle (0.5cm);
\shade [ball color=blue] (180:0.5) circle (0.5cm);
\end{scope}

\begin{scope}[xshift=2cm,yshift=-3cm]
\draw [gray] (0,0,0) circle (1cm);
\shade [ball color=red] (240:0.536) circle (0.4641cm);
\shade [ball color=blue] (0:0.536) circle (0.4641cm);
\shade [ball color=green] (120:0.536) circle (0.4641cm);
\end{scope}

\end{tikzpicture}
\end{document}

I'm primarily interested in a TikZ solution, but solutions using other packages (PSTricks/Asymptote) are welcome. I know Asymptote in particular is probably better suited to such diagrams.

A related question is How to draw a series of simple circle packing illustrations, possibly with Tikz?, which deals with circle packing in a circle.

  • A good question for me and it is very interested to draw a kernel of an atom. – Sebastiano Sep 1 '18 at 6:14
  • Very nice question indeed! But I do think it depends a lot on whether or not you know the correct drawing order on beforehand. If you know the Cartesian coordinates of the inner spheres then the z buffer of pgfplots can order the drawing for you I think. – Max Sep 1 '18 at 7:36
  • Is the question still unanswered? – Dr. Manuel Kuehner Feb 3 at 12:48
8

The theory behind this is actually not very difficult. One way (out of two ways) to make the spheres maximally packed is to put them on the root lattice of A_3=SU(4). The simple roots of A_3 can be chosen to be

\alpha_1=(1,0,0)
\alpha_2=(-1/2,1/\sqrt{2},-1/2)
\alpha_3=(0,0,1)

A lattice point has then the coordinates \sum_i n_i\alpha_i where the n_i\in\mathbbm{Z}. UPDATE: I gave up trying to do that by TeX only and asked Mathematica to compute the projections of the center coordinates of the spheres on the normal of the visible plane. Objects that should be hidden have a more negative projection than objects that could cover them. This yields a lengthy "master list" that can be used to draw the spheres in the right (?) order. In principle, this could be done with pgfplotstable also, but it would be considerably more effort for pgfplotstable dummies like me. The downside of the current answer is that the list has to be recreated for each new set of view angles.

\documentclass[tikz,border=3.14mm]{standalone}
\usepackage{tikz-3dplot}
\usetikzlibrary{3d}
\tikzset{declare function={posx(\x,\y,\z)=\x-\y/2;
posy(\x,\y,\z)=\y/sqrt(2);
posz(\x,\y,\z)=-\y/2+\z;
}}
\newsavebox\Proton
\newsavebox\Neutron
\sbox\Proton{\tikz{\shade[ball color=red] circle({1/sqrt(2)});}}
\sbox\Neutron{\tikz{\shade[ball color=blue] circle({1/sqrt(2)});}}
\begin{document}
% this list has been generated by Mathematica for the present projection
\xdef\MasterList{{{0, 0, 0}}, {{0, 0, 1}, 
  {-1, -1, 0}, {0, -1, 0}, 
  {0, 1, 1}, {-1, 0, 0}, {1, 1, 1}, 
  {0, 0, 0}, {-1, -1, -1}, 
  {1, 0, 0}, {0, -1, -1}, 
  {0, 1, 0}, {1, 1, 0}, 
  {0, 0, -1}}, {{-1, 0, 1}, 
  {0, 0, 1}, {-1, -1, 0}, 
  {1, 0, 1}, {0, -1, 0}, 
  {-1, -2, -1}, {0, 1, 1}, 
  {-1, 0, 0}, {1, 1, 1}, {0, 0, 0}, 
  {-1, -1, -1}, {1, 0, 0}, 
  {0, -1, -1}, {1, 2, 1}, 
  {0, 1, 0}, {-1, 0, -1}, 
  {1, 1, 0}, {0, 0, -1}, 
  {1, 0, -1}}, {{-1, -1, 1}, 
  {0, -1, 1}, {-1, -2, 0}, 
  {0, 1, 2}, {-1, 0, 1}, 
  {-2, -1, 0}, {1, 1, 2}, 
  {0, 0, 1}, {-1, -1, 0}, 
  {-2, -2, -1}, {-1, 1, 1}, 
  {1, 0, 1}, {0, -1, 0}, 
  {-1, -2, -1}, {1, 2, 2}, 
  {0, 1, 1}, {-1, 0, 0}, 
  {-2, -1, -1}, {1, -1, 0}, 
  {0, -2, -1}, {1, 1, 1}, 
  {0, 0, 0}, {-1, -1, -1}, 
  {0, 2, 1}, {-1, 1, 0}, {2, 1, 1}, 
  {1, 0, 0}, {0, -1, -1}, 
  {-1, -2, -2}, {1, 2, 1}, 
  {0, 1, 0}, {-1, 0, -1}, 
  {1, -1, -1}, {2, 2, 1}, 
  {1, 1, 0}, {0, 0, -1}, 
  {-1, -1, -2}, {2, 1, 0}, 
  {1, 0, -1}, {0, -1, -2}, 
  {1, 2, 0}, {0, 1, -1}, 
  {1, 1, -1}}, {{0, 0, 2}, 
  {-1, -1, 1}, {-2, -2, 0}, 
  {0, -1, 1}, {-1, -2, 0}, 
  {0, 1, 2}, {-1, 0, 1}, 
  {-2, -1, 0}, {0, -2, 0}, 
  {1, 1, 2}, {0, 0, 1}, 
  {-1, -1, 0}, {-2, -2, -1}, 
  {0, 2, 2}, {-1, 1, 1}, 
  {-2, 0, 0}, {1, 0, 1}, 
  {0, -1, 0}, {-1, -2, -1}, 
  {1, 2, 2}, {0, 1, 1}, {-1, 0, 0}, 
  {-2, -1, -1}, {1, -1, 0}, 
  {0, -2, -1}, {2, 2, 2}, 
  {1, 1, 1}, {0, 0, 0}, 
  {-1, -1, -1}, {-2, -2, -2}, 
  {0, 2, 1}, {-1, 1, 0}, {2, 1, 1}, 
  {1, 0, 0}, {0, -1, -1}, 
  {-1, -2, -2}, {1, 2, 1}, 
  {0, 1, 0}, {-1, 0, -1}, 
  {2, 0, 0}, {1, -1, -1}, 
  {0, -2, -2}, {2, 2, 1}, 
  {1, 1, 0}, {0, 0, -1}, 
  {-1, -1, -2}, {0, 2, 0}, 
  {2, 1, 0}, {1, 0, -1}, 
  {0, -1, -2}, {1, 2, 0}, 
  {0, 1, -1}, {2, 2, 0}, 
  {1, 1, -1}, {0, 0, -2}}, 
 {{-1, 0, 2}, {-2, -1, 1}, 
  {0, 0, 2}, {-1, -1, 1}, 
  {-2, -2, 0}, {-1, 1, 2}, 
  {-2, 0, 1}, {1, 0, 2}, 
  {0, -1, 1}, {-1, -2, 0}, 
  {-2, -3, -1}, {0, 1, 2}, 
  {-1, 0, 1}, {-2, -1, 0}, 
  {1, -1, 1}, {0, -2, 0}, 
  {-1, -3, -1}, {1, 1, 2}, 
  {0, 0, 1}, {-1, -1, 0}, 
  {-2, -2, -1}, {0, 2, 2}, 
  {-1, 1, 1}, {2, 1, 2}, 
  {-2, 0, 0}, {1, 0, 1}, 
  {0, -1, 0}, {-1, -2, -1}, 
  {-2, -3, -2}, {1, 2, 2}, 
  {0, 1, 1}, {-1, 0, 0}, {2, 0, 1}, 
  {-2, -1, -1}, {1, -1, 0}, 
  {0, -2, -1}, {-1, -3, -2}, 
  {2, 2, 2}, {1, 1, 1}, {0, 0, 0}, 
  {-1, -1, -1}, {-2, -2, -2}, 
  {1, 3, 2}, {0, 2, 1}, {-1, 1, 0}, 
  {2, 1, 1}, {-2, 0, -1}, 
  {1, 0, 0}, {0, -1, -1}, 
  {-1, -2, -2}, {2, 3, 2}, 
  {1, 2, 1}, {0, 1, 0}, 
  {-1, 0, -1}, {2, 0, 0}, 
  {-2, -1, -2}, {1, -1, -1}, 
  {0, -2, -2}, {2, 2, 1}, 
  {1, 1, 0}, {0, 0, -1}, 
  {-1, -1, -2}, {1, 3, 1}, 
  {0, 2, 0}, {-1, 1, -1}, 
  {2, 1, 0}, {1, 0, -1}, 
  {0, -1, -2}, {2, 3, 1}, 
  {1, 2, 0}, {0, 1, -1}, 
  {-1, 0, -2}, {2, 0, -1}, 
  {1, -1, -2}, {2, 2, 0}, 
  {1, 1, -1}, {0, 0, -2}, 
  {2, 1, -1}, {1, 0, -2}}, 
 {{-1, 0, 2}, {-2, -1, 1}, 
  {0, 0, 2}, {-1, -1, 1}, 
  {-2, -2, 0}, {-1, 1, 2}, 
  {-2, 0, 1}, {1, 0, 2}, 
  {0, -1, 1}, {-1, -2, 0}, 
  {-2, -3, -1}, {0, 1, 2}, 
  {-1, 0, 1}, {-2, -1, 0}, 
  {1, -1, 1}, {0, -2, 0}, 
  {-1, -3, -1}, {1, 1, 2}, 
  {0, 0, 1}, {-1, -1, 0}, 
  {-2, -2, -1}, {0, 2, 2}, 
  {-1, 1, 1}, {2, 1, 2}, 
  {-2, 0, 0}, {1, 0, 1}, 
  {0, -1, 0}, {-1, -2, -1}, 
  {-2, -3, -2}, {1, 2, 2}, 
  {0, 1, 1}, {-1, 0, 0}, {2, 0, 1}, 
  {-2, -1, -1}, {1, -1, 0}, 
  {0, -2, -1}, {-1, -3, -2}, 
  {2, 2, 2}, {1, 1, 1}, {0, 0, 0}, 
  {-1, -1, -1}, {-2, -2, -2}, 
  {1, 3, 2}, {0, 2, 1}, {-1, 1, 0}, 
  {2, 1, 1}, {-2, 0, -1}, 
  {1, 0, 0}, {0, -1, -1}, 
  {-1, -2, -2}, {2, 3, 2}, 
  {1, 2, 1}, {0, 1, 0}, 
  {-1, 0, -1}, {2, 0, 0}, 
  {-2, -1, -2}, {1, -1, -1}, 
  {0, -2, -2}, {2, 2, 1}, 
  {1, 1, 0}, {0, 0, -1}, 
  {-1, -1, -2}, {1, 3, 1}, 
  {0, 2, 0}, {-1, 1, -1}, 
  {2, 1, 0}, {1, 0, -1}, 
  {0, -1, -2}, {2, 3, 1}, 
  {1, 2, 0}, {0, 1, -1}, 
  {-1, 0, -2}, {2, 0, -1}, 
  {1, -1, -2}, {2, 2, 0}, 
  {1, 1, -1}, {0, 0, -2}, 
  {2, 1, -1}, {1, 0, -2}}, 
 {{-1, -2, 1}, {-1, 0, 2}, 
  {-2, -1, 1}, {0, 0, 2}, 
  {-1, -1, 1}, {-2, -2, 0}, 
  {-1, 1, 2}, {-2, 0, 1}, 
  {1, 0, 2}, {0, -1, 1}, 
  {-1, -2, 0}, {-2, -3, -1}, 
  {1, 2, 3}, {0, 1, 2}, {-1, 0, 1}, 
  {-2, -1, 0}, {1, -1, 1}, 
  {-3, -2, -1}, {0, -2, 0}, 
  {-1, -3, -1}, {1, 1, 2}, 
  {0, 0, 1}, {-1, -1, 0}, 
  {-2, -2, -1}, {0, 2, 2}, 
  {-1, 1, 1}, {2, 1, 2}, 
  {-2, 0, 0}, {1, 0, 1}, 
  {0, -1, 0}, {-1, -2, -1}, 
  {-2, -3, -2}, {1, 2, 2}, 
  {0, 1, 1}, {-1, 0, 0}, {2, 0, 1}, 
  {-2, -1, -1}, {1, -1, 0}, 
  {0, -2, -1}, {-1, -3, -2}, 
  {-1, 2, 1}, {2, 2, 2}, {1, 1, 1}, 
  {0, 0, 0}, {-1, -1, -1}, 
  {-2, -2, -2}, {1, -2, -1}, 
  {1, 3, 2}, {0, 2, 1}, {-1, 1, 0}, 
  {2, 1, 1}, {-2, 0, -1}, 
  {1, 0, 0}, {0, -1, -1}, 
  {-1, -2, -2}, {2, 3, 2}, 
  {1, 2, 1}, {0, 1, 0}, 
  {-1, 0, -1}, {2, 0, 0}, 
  {-2, -1, -2}, {1, -1, -1}, 
  {0, -2, -2}, {2, 2, 1}, 
  {1, 1, 0}, {0, 0, -1}, 
  {-1, -1, -2}, {1, 3, 1}, 
  {0, 2, 0}, {3, 2, 1}, 
  {-1, 1, -1}, {2, 1, 0}, 
  {1, 0, -1}, {0, -1, -2}, 
  {-1, -2, -3}, {2, 3, 1}, 
  {1, 2, 0}, {0, 1, -1}, 
  {-1, 0, -2}, {2, 0, -1}, 
  {1, -1, -2}, {2, 2, 0}, 
  {1, 1, -1}, {0, 0, -2}, 
  {2, 1, -1}, {1, 0, -2}, 
  {1, 2, -1}}}
\xdef\LstCol{"red","blue"}
\tdplotsetmaincoords{-90+109.471}{-90+70}
\foreach \Lst in \MasterList
{\typeout{\Lst}
\begin{tikzpicture}
\path[use as bounding box] (-3.5,-3.5) rectangle (3.5,3.5);
\draw (0,0) circle ({1}); % /sqrt(2)
%\node at (1,1) {\Y,\X};
\begin{scope}[tdplot_main_coords]
 \draw[-latex] (0,0,0) coordinate (O) -- (1,0,0) node[right]{$\alpha_1$};
 \draw[-latex] (O) -- (-1/2,{1/sqrt(2)},-1/2) node[right]{$\alpha_2$};
 \draw[-latex] (O) -- (0,0,1) node[right]{$\alpha_3$};
 \draw[red,-latex] (O) -- (1/2,{1/sqrt(2)},1/2) node[right]{$-\theta$};
 \foreach \Z in \Lst
  {\typeout{\Z}
  \pgfmathsetmacro{\myx}{{\Z}[0]}
  \pgfmathsetmacro{\myy}{{\Z}[1]}
  \pgfmathsetmacro{\myz}{{\Z}[2]}
  \pgfmathtruncatemacro{\mycol}{int(2*rnd)}
  \ifnum\mycol=1
  \node at ({posx(\myx,\myy,\myz)},
  {posy(\myx,\myy,\myz)},{posz(\myx,\myy,\myz)}) {\usebox\Neutron};
  \else
  \node at ({posx(\myx,\myy,\myz)},
  {posy(\myx,\myy,\myz)},{posz(\myx,\myy,\myz)}) {\usebox\Proton};
  \fi}
\end{scope}
\end{tikzpicture}}
\end{document}

enter image description here

OLD ANSWER: The only problem I have (I think) is to adjust the order in which the spheres are drawn (or, equivalently, to dial the right view angles for the simple-minded order I chose).

\documentclass[tikz,border=3.14mm]{standalone}
\usepackage{tikz-3dplot}
\usetikzlibrary{3d}%{n1 - n2/2, n2/Sqrt[2], -n2/2 + n3}
\tikzset{declare function={posx(\x,\y,\z)=\x-\y/2;
posy(\x,\y,\z)=\y/sqrt(2);
posz(\x,\y,\z)=-\y/2+\z;
}}
\newsavebox\Proton
\newsavebox\Neutron
\sbox\Proton{\tikz{\shade[ball color=red] circle({1/sqrt(2)});}}
\sbox\Neutron{\tikz{\shade[ball color=blue] circle({1/sqrt(2)});}}
\begin{document}
\xdef\LstCol{"red","blue"}
\foreach \Lev in {0,...,4}
{\tdplotsetmaincoords{109.471}{0}
\begin{tikzpicture}
\path[use as bounding box] (-3.5,-3.5) rectangle (3.5,3.5);
\draw (0,0) circle ({1}); % /sqrt(2)
%\node at (1,1) {\Y,\X};
\begin{scope}[tdplot_main_coords]
 \draw[-latex] (0,0,0) coordinate (O) -- (1,0,0) node[right]{$\alpha_1$};
 \draw[-latex] (O) -- (-1/2,{1/sqrt(2)},-1/2) node[right]{$\alpha_2$};
 \draw[-latex] (O) -- (0,0,1) node[right]{$\alpha_3$};
 \draw[red,-latex] (O) -- (1/2,{1/sqrt(2)},1/2) node[right]{$-\theta$};
 % level 0
 \ifnum\Lev>0
  \pgfmathtruncatemacro{\mycol}{int(2*rnd)}
  \ifnum\mycol=1
  \node at (0,0,0) {\usebox\Neutron};
  \else
  \node at (0,0,0) {\usebox\Proton};
  \fi
 \fi
 % level 1
 \ifnum\Lev>1
  \foreach \Z in {{-1, -1, -1}, {-1, -1, 0}, 
  {-1, 0, 0}, {0, -1, -1}, 
  {0, -1, 0}, {0, 0, -1}, {0, 0, 1}, 
  {0, 1, 0}, {0, 1, 1}, {1, 0, 0}, 
  {1, 1, 0}, {1, 1, 1}}
  {\pgfmathsetmacro{\myx}{{\Z}[0]}
  \pgfmathsetmacro{\myy}{{\Z}[1]}
  \pgfmathsetmacro{\myz}{{\Z}[2]}
  \pgfmathtruncatemacro{\mycol}{int(2*rnd)}
  \ifnum\mycol=1
  \node at ({posx(\myx,\myy,\myz)},
  {posy(\myx,\myy,\myz)},{posz(\myx,\myy,\myz)}) {\usebox\Neutron};
  \else
  \node at ({posx(\myx,\myy,\myz)},
  {posy(\myx,\myy,\myz)},{posz(\myx,\myy,\myz)}) {\usebox\Proton};
  \fi}
 \fi
 % level 2
 \ifnum\Lev>2
 \foreach \Z in {{-1, -2, -1}, {-1, 0, -1}, {-1, 0, 1}, {1, 0, -1}, {1, 0, 1}, {1, 2, 
  1}}
  {\pgfmathsetmacro{\myx}{{\Z}[0]}
 \pgfmathsetmacro{\myy}{{\Z}[1]}
 \pgfmathsetmacro{\myz}{{\Z}[2]}
 \pgfmathtruncatemacro{\mycol}{int(2*rnd)}
 \ifnum\mycol=1
 \node at ({posx(\myx,\myy,\myz)},
 {posy(\myx,\myy,\myz)},{posz(\myx,\myy,\myz)}) {\usebox\Neutron};
 \else
 \node at ({posx(\myx,\myy,\myz)},
 {posy(\myx,\myy,\myz)},{posz(\myx,\myy,\myz)}) {\usebox\Proton};
 \fi}
 \fi
 % level 3
 \ifnum\Lev>3 
  \foreach \Z in {{-2, -2, -1}, {-2, -1, -1}, {-2, -1, 0}, {-1, -2, -2}, {-1, -2, 
                0}, {-1, -1, -2}, {-1, -1, 1}, {-1, 1, 0}, {-1, 1, 
   1}, {0, -2, -1}, {0, -1, -2}, {0, -1, 1}, {0, 1, -1}, {0, 1, 2}, {0,
    2, 1}, {1, -1, -1}, {1, -1, 0}, {1, 1, -1}, {1, 1, 2}, {1, 2, 
   0}, {1, 2, 2}, {2, 1, 0}, {2, 1, 1}, {2, 2, 1}}  
   {\pgfmathsetmacro{\myx}{{\Z}[0]}
  \pgfmathsetmacro{\myy}{{\Z}[1]}
  \pgfmathsetmacro{\myz}{{\Z}[2]}
  \pgfmathtruncatemacro{\mycol}{int(2*rnd)}
  \ifnum\mycol=1
  \node at ({posx(\myx,\myy,\myz)},
  {posy(\myx,\myy,\myz)},{posz(\myx,\myy,\myz)}) {\usebox\Neutron};
  \else
  \node at ({posx(\myx,\myy,\myz)},
  {posy(\myx,\myy,\myz)},{posz(\myx,\myy,\myz)}) {\usebox\Proton};
  \fi}
 \fi
\end{scope}
\end{tikzpicture}}%}}
\end{document}

enter image description here

If I were to skip level 2, I think it would be fine. Perhaps that's the way to go because these spheres are partly covered by those of level 1.

  • +1 Really cool, great work!! – Max Sep 1 '18 at 15:51
5

This is only a start and I used some 'unconventional' methods so maybe it's not really helpful, but I will just throw it out here. Lets start with the result so maybe you keep on reading :)

enter image description here

As mentioned in my comment, I assumed that the 3D Cartesian coordinates of the inner spheres are known, and I use the z buffer=sort of the pgfplots package to determine the drawing order.

I defined a style sphere packing axis that sets the needed axis options, and re-defines the view key to set the x, y, and z vectors to unit length.

\makeatletter
\pgfplotsset{
    sphere packing axis/.style={
        hide axis,
        clip=false,
        z buffer=sort,
        % Redefine view={<azimuth>}{<elevation>} key
        view/.code 2 args={%
            % Set elevation and azimuth angles
            \pgfmathsetmacro\view@az{##1}
            \pgfmathsetmacro\view@el{##2}
            % Calculate projections of rotation matrix
            \pgfmathsetmacro\xvec@x{cos(\view@az)}
            \pgfmathsetmacro\xvec@y{-sin(\view@az)*sin(\view@el)}
            \pgfmathsetmacro\yvec@x{sin(\view@az)}
            \pgfmathsetmacro\yvec@y{cos(\view@az)*sin(\view@el)}
            \pgfmathsetmacro\zvec@x{0}
            \pgfmathsetmacro\zvec@y{cos(\view@el)}
            % Set base vectors
            \pgfkeysalso{
                x={(\xvec@x cm,\xvec@y cm)},
                y={(\yvec@x cm,\yvec@y cm)},
                z={(\zvec@x cm,\zvec@y cm)},
            }
        },
    }
}
\makeatother 

I use a outer- and inner radius key to set the dimensions of the spheres. This is not really needed but it is convenient I think.

\tikzset{
    outer sphere radius/.store in=\spherepackingouterradius,
    inner sphere radius/.store in=\spherepackinginnerradius,
}

I defined a new plot mark, that is simply a shaded circle. Still have to figure out the coloring.

\pgfdeclareplotmark{sphere}{
    \fill[ball color=red,draw=none] (0,0) circle (\spherepackinginnerradius);
}

Finally I use the definitions from above to draw the inner spheres with known coordinates, and the outer sphere on top of it.

\begin{document}
    \begin{tikzpicture}[outer sphere radius=1cm,inner sphere radius=0.4142cm]
        \begin{axis}[sphere packing axis,view={25}{30}]
            \addplot3[mark=sphere,draw=none] coordinates{
                (0,0,0.5858)
                (0,0,-0.5858)
                ( 0.4142, 0.4142,0)
                ( 0.4142,-0.4142,0)
                (-0.4142,-0.4142,0)
                (-0.4142, 0.4142,0)
            };
            \shade[ball color=black,opacity=0.1] (axis cs:0,0,0) circle (\spherepackingouterradius);
        \end{axis}
    \end{tikzpicture}
\end{document}

Edit
I had to make up for not including a MWE by adding some more examples, for N=2,3,4:

enter image description here

Edit 2
I got the colors working, and apparently there was already a ball mark defined.

enter image description here

MWE:

\documentclass[margin=2mm]{standalone}

\usepackage{pgfplots}

\makeatletter
\pgfplotsset{
    sphere packing axis/.style={
        hide axis,
        clip=false,
        z buffer=sort,
        colormap={bluered}{
            rgb255(0cm)=(0,0,180); rgb255(1cm)=(0,255,255); rgb255(2cm)=(100,255,0);
            rgb255(3cm)=(255,255,0); rgb255(4cm)=(255,0,0); rgb255(5cm)=(128,0,0)},
        every axis plot/.style={
            mark=ball,
            scatter,
            point meta=explicit,
            mark size=\spherepackinginnerradius,
            scatter/use mapped color={ball color=mapped color},
            mark options={draw opacity=0},
        },
        % Redefine view={<azimuth>}{<elevation>} key
        view/.code 2 args={%
            % Set elevation and azimuth angles
            \pgfmathsetmacro\view@az{##1}
            \pgfmathsetmacro\view@el{##2}
            % Calculate projections of rotation matrix
            \pgfmathsetmacro\xvec@x{cos(\view@az)}
            \pgfmathsetmacro\xvec@y{-sin(\view@az)*sin(\view@el)}
            \pgfmathsetmacro\yvec@x{sin(\view@az)}
            \pgfmathsetmacro\yvec@y{cos(\view@az)*sin(\view@el)}
            \pgfmathsetmacro\zvec@x{0}
            \pgfmathsetmacro\zvec@y{cos(\view@el)}
            % Set base vectors
            \pgfkeysalso{
                x={(\xvec@x cm,\xvec@y cm)},
                y={(\yvec@x cm,\yvec@y cm)},
                z={(\zvec@x cm,\zvec@y cm)},
            }
        },
    }
}
\makeatother 


\tikzset{
    outer sphere radius/.store in=\spherepackingouterradius,
    inner sphere radius/.store in=\spherepackinginnerradius,
}

\begin{document}
    \begin{tikzpicture}[outer sphere radius=1cm,inner sphere radius=0.5cm]
        \begin{axis}[sphere packing axis,view={25}{30}]
            \addplot3[] coordinates{
                (0,0, 0.5) [0]
                (0,0,-0.5) [1]
            };
            \shade[ball color=black,opacity=0.1] (axis cs:0,0,0) circle (\spherepackingouterradius);
        \end{axis}
    \end{tikzpicture}
    \begin{tikzpicture}[outer sphere radius=1cm,inner sphere radius=0.4641cm]
        \begin{axis}[sphere packing axis,view={25}{30}]
            \addplot3[] coordinates{
                ( 0,      0.5359,0) [0]
                (-0.4641,-0.2679,0) [1]
                ( 0.4641,-0.2679,0) [2]
            };
            \shade[ball color=black,opacity=0.1] (axis cs:0,0,0) circle (\spherepackingouterradius);
        \end{axis}
    \end{tikzpicture}
    \begin{tikzpicture}[outer sphere radius=1cm,inner sphere radius=0.4494cm]
        \begin{axis}[sphere packing axis,view={25}{30}]
            \addplot3[]coordinates{
                ( 0,      0,      0.5505) [0]
                (-0.4495,-0.2595,-0.1835) [1]
                ( 0.4495,-0.2595,-0.1835) [2] 
                ( 0,      0.5190,-0.1835) [3]
            };
            \shade[ball color=black,opacity=0.1] (axis cs:0,0,0) circle (\spherepackingouterradius);
        \end{axis}
    \end{tikzpicture}
    \begin{tikzpicture}[outer sphere radius=1cm,inner sphere radius=0.4142cm]
        \begin{axis}[sphere packing axis,view={25}{30}]
            \addplot3[] coordinates{
                ( 0,      0,     0.5858) [0]
                ( 0,      0,    -0.5858) [1] 
                ( 0.4142, 0.4142,0     ) [2]
                ( 0.4142,-0.4142,0     ) [3]
                (-0.4142,-0.4142,0     ) [4]
                (-0.4142, 0.4142,0     ) [5]
            };
            \shade[ball color=black,opacity=0.1] (axis cs:0,0,0) circle (\spherepackingouterradius);
        \end{axis}
    \end{tikzpicture}
\end{document}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.