0

I am wanting to use the code provided by Tom Bombadil to 3D bodies in TikZ that creates nice looking spheres, namely (with a slight adaption for showing the radius):

\draw (-1,0) arc (180:360:1cm and 0.5cm);%
\draw[dashed] (-1,0) arc (180:0:1cm and 0.5cm);%
\draw (0,1) arc (90:270:0.5cm and 1cm);%
\draw[dashed] (0,1) arc (90:-90:0.5cm and 1cm);%
\draw (0,0) circle (1cm);%
\shade[ball color=blue!10!white,opacity=0.20] (0,0) circle (1cm);%
\fill[fill=black] (0,0) circle (1pt);%
\draw[dashed] (0,0) -- node[above left]{$r$} (1,0);%

which produces:

enter image description here

I am having difficulty in converting this code into a command that can be placed at arbitrary locations with the radius changed to another value that then updates the dependent values. My attempts do not work when using the \the\numexpr#3/2cm etc and I am not familiar enough with tikz as yet. For instance, when using a simpler sphere code this is how my attempts at making it adaptable to different coordinates worked out:

enter image description here

My use case is to show 4-residue at a time spherical-searches of PDB alpha-carbon files to find helices (if all 4 alpha-carbon points lie in the sphere, high likelihood that it is in a helix region), which looks like this in my main standalone document:

enter image description here

How can I convert the above code into a custom command that can be placed at arbitrary locations and a modifiable radius please? Apologies that this is basic but I have been trying for half an hour and if I am struggling then perhaps others would too, would appreciate a duplicate if so (I have tried searching on here).

\documentclass[border=0pt,tikz]{standalone}

\begin{document}% \newcommand\drawsphere[3]{% \draw (-1,0) arc (180:360:1cm and 0.5cm);% \draw[dashed] (-1,0) arc (180:0:1cm and 0.5cm);% \draw (0,1) arc (90:270:0.5cm and 1cm);% \draw[dashed] (0,1) arc (90:-90:0.5cm and 1cm);% \draw (0,0) circle (1cm);% \shade[ball color=blue!10!white,opacity=0.40] (0,0) circle (1cm);% \fill[fill=black] (0,0) circle (1pt);% \draw[dashed] (0,0) -- node[above left]{$r$} (1,0);% }% \begin{tikzpicture}% \draw (-1,0) arc (180:360:1cm and 0.5cm);% \draw[dashed] (-1,0) arc (180:0:1cm and 0.5cm);% \draw (0,1) arc (90:270:0.5cm and 1cm);% \draw[dashed] (0,1) arc (90:-90:0.5cm and 1cm);% \draw (0,0) circle (1cm);% \shade[ball color=blue!10!white,opacity=0.20] (0,0) circle (1cm);% \fill[fill=black] (0,0) circle (1pt);% \draw[dashed] (0,0) -- node[above left]{$r$} (1,0);% \end{tikzpicture} \end{document}

JamesT
  • 3,169
  • 3
    Use ``\picinstead of\newcommand, which you can place like nodes: https://tikz.dev/tikz-pics . Searching forargs` shows you how to pass parameters to a pic. – MS-SPO Aug 30 '23 at 11:32
  • 4
    Be careful mixing canvas coordinates/radii (the ones with unit) and those of the xyz coordinate system (the one without units). Out of the box, PGF/TikZ defaults to 1 = 1cm and parallel axes so you're good here but full portability would look differently. (In this case, simply remove all cms but leave the 1pt but also see my comment to Rmano's answer.) – Qrrbrbirlbel Aug 30 '23 at 12:02

2 Answers2

3

Although using pics would be better, a quick-and-dirty way:

\documentclass[border=2.7mm,tikz]{standalone}
\newcommand\drawsphere[3]{%scale, x, y
    \begin{scope}[scale=#1, shift={(#2,#3)}]
        \draw (-1,0) arc (180:360:1cm and 0.5cm);
        \draw[dashed] (-1,0) arc (180:0:1cm and 0.5cm);
        \draw (0,1) arc (90:270:0.5cm and 1cm);
        \draw[dashed] (0,1) arc (90:-90:0.5cm and 1cm);
        \draw (0,0) circle (1cm);
        \shade[ball color=blue!10!white,opacity=0.40] (0,0) circle (1cm);
        \fill[fill=black] (0,0) circle (1pt);
        \draw[dashed] (0,0) -- node[above left]{$r$} (1,0);
    \end{scope}
}
\begin{document}
\begin{tikzpicture}
    \drawsphere{1}{0}{0}
    \drawsphere{2}{2}{2}
    \drawsphere{0.5}{-1}{-1}
\end{tikzpicture}
\end{document}

enter image description here

As noticed by Qrrbrbirlbel, the order of the scale option is important (scaling also the shift coordinates here), and also the central dot got scaled. Maybe a better implementation is

\documentclass[border=2.7mm,tikz]{standalone}
\newcommand\drawsphere[3]{%scale, x, y
    \begin{scope}[shift={(#2,#3)}, scale=#1,
            % transform shape % if you want the "r" scaled too
        ]
        \draw (-1,0) arc (180:360:1 and 0.5);
        \draw[dashed] (-1,0) arc (180:0:1 and 0.5);
        \draw (0,1) arc (90:270:0.5 and 1);
        \draw[dashed] (0,1) arc (90:-90:0.5 and 1);
        \draw (0,0) circle (1);
        \shade[ball color=blue!10!white,opacity=0.40] (0,0) circle (1);
        \draw[dashed] (0,0) -- node[above left]{$r$} (1,0);
    \end{scope}
    \fill[black] (#2,#3) circle [radius=1pt];
}
\begin{document}
\begin{tikzpicture}
    \drawsphere{1}{0}{0}
    \drawsphere{2}{2}{2}
    \drawsphere{0.5}{-1}{-1}
\end{tikzpicture}
\end{document}

enter image description here

Rmano
  • 40,848
  • 3
  • 64
  • 125
  • 1
    It should be noted that the order of scale and shift matter. The second sphere is placed at (4, 4) while the small one is placed at (−0.5, −0.5).` And this also scales the dot in the middle. – Qrrbrbirlbel Aug 30 '23 at 11:57
  • Ah, yes, you are right. Probably it's better to switch the order; it's more intuitive. – Rmano Aug 30 '23 at 12:52
1

Here are some ways to do it with \pics, also showing work left to do. Main topics:

  1. using \pic without parameter arguments
  2. using \pic with parameter arguments

1. without arguments

Simply rework the \newcommand like this:

 \begin{tikzpicture}[
    sph/.pic={% ~~~ with fixed radius ~~~~~~~~~
        \draw (-1,0) arc (180:360:1cm and 0.5cm);%
        \draw[dashed] (-1,0) arc (180:0:1cm and 0.5cm);%
        \draw (0,1) arc (90:270:0.5cm and 1cm);%
        \draw[dashed] (0,1) arc (90:-90:0.5cm and 1cm);%
        \draw (0,0) circle (1cm);%
        \shade[ball color=blue!10!white,opacity=0.20] (0,0) circle (1cm);%
        \fill[fill=black] (0,0) circle (1pt);%
        \draw[dashed] (0,0) -- node[above left]{$r$} (1,0);%    
        }
    ]
...

and call it a bit like a \node, where the node here just acts as a caption:

    \pic at (0,0) {sph}; \node at (0,-1.3){1};

Now pics 1-5 show some variations of this call:

  1. regular call
  2. different color, rotated !! internal label "r" needs rework
  3. same, made smaller >> unchanged label "r"
  4. like 3, but subjecting also the label to scaling
  5. enlarging it
  6. miscounted for a reason == missing

result

with arguments

The \tikzset in the beginning shows you how to do it, while the call to use it is just --- kindly recognize passing the parameter:

\pic at (45:5) {sphr={2cm}};

Now, as you can see in picture 7 the work remains unfinished, as a bit more calculations are needed for all the arcs ... it's not just replacing 1cm by #1. Perhaps the design approach here should be thought over and improved.

I.e. a successful rework needs to replace all hardcoded:

  • 1cm
  • +1 coordinate
  • -1 coordinate
  • calculate the half of #1 to replace the 0.5cm

This can probably done better right from the start ... like:

\documentclass[10pt,border=3mm,tikz]{standalone}

\tikzset{% ~~~ unfinished sketch for \pic taking argument(s) ~~~ pics/sphr/.style args={#1}{% #1=radius, obviously code={ \draw (-1,0) arc (180:360:#1 and 0.5cm);% \draw[dashed] (-1,0) arc (180:0:1cm and 0.5cm);% \draw ( 0,1) arc (90:270:0.5cm and 1cm);% \draw[dashed] ( 0,1) arc (90:-90:0.5cm and 1cm);% \draw ( 0,0) circle (#1);% \shade[ball color=blue!10!white,opacity=0.20] ( 0,0) circle (#1);% \fill[fill=black] ( 0,0) circle (1pt);% \draw[dashed] ( 0,0) -- node[above left]{$r$} (1,0);%
} } }

\begin{document} \begin{tikzpicture}[ sph/.pic={% ~~~ with fixed radius ~~~~~~~~~ \draw (-1,0) arc (180:360:1cm and 0.5cm);% \draw[dashed] (-1,0) arc (180:0:1cm and 0.5cm);% \draw (0,1) arc (90:270:0.5cm and 1cm);% \draw[dashed] (0,1) arc (90:-90:0.5cm and 1cm);% \draw (0,0) circle (1cm);% \shade[ball color=blue!10!white,opacity=0.20] (0,0) circle (1cm);% \fill[fill=black] (0,0) circle (1pt);% \draw[dashed] (0,0) -- node[above left]{$r$} (1,0);%
} ]

\pic                            at (0,0) {sph}; \node at (0,-1.3){1};
\pic[red,rotate=30]             at (5,0) {sph}; \node at (5,-1.3){2};
\pic[scale=.5]                  at (3,0) {sph}; \node at (3,-.8 ){3};
\pic[scale=.5,transform shape]  at (3,-2) {sph};\node at (3,-2.8){4};
\pic[scale=2]                   at (-2,3) {sph};\node at (-2,.6){5};

\pic                            at (45:5) {sphr={2cm}}; \node at (20:5.5){7};

\end{tikzpicture} \end{document}

MS-SPO
  • 11,519