Electric field lines of two charges

The electric field line and equipotential surfaces of two point charges: same-sign or opposite charge.

electric_fieldlines2-001.pngelectric_fieldlines2-002.pngelectric_fieldlines2-003.pngelectric_fieldlines2-004.pngelectric_fieldlines2-005.pngelectric_fieldlines2-006.png

Download and compile the code below if you like, or try in Overleaf. Please note you may need to remove some tikzpicture pieces to avoid Overleaf’s time limit for compilation.

% Author: Izaak Neutelings (July 2018)
% page 8 https://archive.org/details/StaticAndDynamicElectricity
% https://stackoverflow.com/questions/4919827/gnuplot-with-texshop-in-osx --shell-escape
% https://tex.stackexchange.com/questions/56353/extract-x-y-coordinate-of-an-arbitrary-point-on-curve-in-tikz
% https://tex.stackexchange.com/questions/412899/tikz-calculate-and-store-the-euclidian-distance-between-two-coordinates

\documentclass[border=3pt,tikz]{standalone}
\usepackage{amsmath} % for \dfrac
\usepackage{bm}
\usepackage{tikz,pgfplots}
\tikzset{>=latex} % for LaTeX arrow head
\pgfplotsset{compat=1.13}
\usetikzlibrary{decorations.markings,intersections,calc}
\usepackage{ifthen}
%\usepackage{etoolbox}
\usepackage{xcolor}
\colorlet{Ecol}{orange!90!black}
\colorlet{EcolFL}{orange!80!black}
\colorlet{Bcol}{blue!90!black}
\tikzstyle{EcolEP}=[blue!80!white]
\tikzstyle{charge+}=[very thin,top color=red!50,bottom color=red!90!black,shading angle=20]
\tikzstyle{charge-}=[very thin,top color=blue!50,bottom color=blue!80,shading angle=20]
%\tikzstyle{EFielLineArrow2}=[
%    EcolFL,decoration={markings,
%          mark=at position 0.5 with {\arrow[rotate=\angle]{latex}}},
%          postaction={decorate}]
\tikzset{
   EFielLineArrow/.style args = {#1}{EcolFL,decoration={markings,
          mark=at position 0.5 with {\arrow[rotate=#1]{latex}}},
          postaction={decorate}}
}

\makeatletter
  \newcommand{\xy}[3]{% % FIND X, Y
    \tikz@scan@one@point\pgfutil@firstofone#1\relax
    \edef#2{\the\pgf@x}%
    \edef#3{\the\pgf@y}%
  }
\makeatother
\newcommand{\EFielLineArrow}[2]{ % ELECTRIC FIELD LINE ARROW
  \pgfkeys{/pgf/fpu,/pgf/fpu/output format=fixed} % for calculation between -1*10^324 and +1*10^324
  \pgfmathsetmacro{\x}{#1/28.45pt}
  \pgfmathsetmacro{\y}{#2/28.45pt}
  \pgfmathsetmacro{\U}{\Q*((\x+\a)^2+(\y)^2)^(3/2)}
  \pgfmathsetmacro{\V}{\q*((\x-\a)^2+(\y)^2)^(3/2)}
  \pgfkeys{/pgf/fpu=false}
  \pgfmathparse{
    atan2(((\y)*\V + (\y)*\U),((\x+\a)*\V + (\x-\a)*\U))
  }
  \edef\angle{\pgfmathresult}
  \pgfmathsetmacro{\D}{int(1000*\q*(\x+\a)/sqrt((\x+\a)^2+\y*\y) + 1000*\Q*(\x-\a)/sqrt((\x-\a)^2+\y*\y))/1000}
  \draw[EFielLineArrow={\angle}] (\xpt,\ypt);
}
\newcommand{\EVector}[2]{ % ELECTRIC FIELD VECTOR
  \pgfmathsetmacro{\x}{#1/28.45pt}
  \pgfmathsetmacro{\y}{#2/28.45pt}
  \pgfmathsetmacro{\U}{((\x+\a)^2+(\y)^2)^(3/2)}
  \pgfmathsetmacro{\V}{((\x-\a)^2+(\y)^2)^(3/2)}
  \pgfmathsetmacro{\Ex}{\q*3*(\x+\a)/\U + \Q*3*(\x-\a)/\V}
  \pgfmathsetmacro{\Ey}{\q*3*(\y)/\U + \Q*3*(\y)/\V}
  \fill[Ecol] (\x,\y) circle (0.8pt);
  \draw[->,Ecol,thick] (\x,\y) --++ (\Ex,\Ey)
    node[Ecol,right,scale=0.8] {$\bm{E}$};
  \pgfmathsetmacro{\D}{int(1000*\q*(\x+\a)/sqrt((\x+\a)^2+\y*\y) + 1000*\Q*(\x-\a)/sqrt((\x-\a)^2+\y*\y))/1000}
}
\newcommand{\EFieldLines}{ % ELECTRIC FIELD LINES
  \message{^^JField lines (\q,\Q) with contours range ^^J\range^^J}
  
  % PATHS for intersections
  \path[name path=ellipse1] (-\a,0) ellipse ({0.90*\R} and {1.5*\R});
  \path[name path=ellipse2] (+\a,0) ellipse ({0.75*\R} and {1.5*\R});
  \path[name path=ellipse3] (  0,0) ellipse ({\a+\R} and 1.5*\R);
  
  % FIELD LINES
  \draw[EcolFL,name path=Elines] plot[id=plot, raw gnuplot, smooth]
    function{
       f(x,y) = \q*(x+\a)/sqrt((x+\a)**2+y**2) + \Q*(x-\a)/sqrt((x-\a)**2+y**2);
       set xrange [\xmin:\xmax];
       set yrange [-\ymax:\ymax];
       set view 0,0;
       set isosample 400,400;
       set cont base;
       set cntrparam levels discrete \range;
       unset surface;
       splot f(x,y)
    };
  
  % ELLIPSE INTERSECTIONS
  \pgfmathsetmacro{\oppositesign}{\q*\Q<0 ? 1 : 0}
  \ifthenelse{\oppositesign>0}{
    % OPPOSITE SIGN
    \foreach \c in {1,2}{
      \message{Intersections \c...}
      \path[name intersections={of=Elines and ellipse\c,total=\t}]
        \pgfextra{\xdef\Nb{\t}};
      \message{ found \Nb ^^J}
      \foreach \i in {1,...,\Nb}{
        \message{  \i}
        \xy{(intersection-\i)}{\xpt}{\ypt}
        \EFielLineArrow{\xpt}{\ypt}
        \message{ (\D,\x,\y)^^J}
      }
    }
  }{
    % SAME SIGN
    \message{Intersections...}
    \path[name intersections={of=Elines and ellipse3,total=\t}]
        \pgfextra{\xdef\Nb{\t}}; 
    \message{ found \Nb ^^J}
    \foreach \i in {1,...,\Nb}{
      \message{  \i}
      \xy{(intersection-\i)}{\xpt}{\ypt}
      \EFielLineArrow{\xpt}{\ypt}
      \message{ (\D,\x,\y)^^J}
    }
  }
}
\newcommand{\EEquipot}{ % EQUIPOTENTIAL SURFACE
  \message{^^JEquipotential surface (\q,\Q) with contours range ^^J\rangeEP}
  
  % FIELD LINES
  \draw[EcolEP] plot[id=plot, raw gnuplot, smooth] %,dashed
    function{
       f(x,y) = \q/sqrt((x+\a)**2+y**2) + \Q/sqrt((x-\a)**2+y**2);
       set xrange [\xmin:\xmax];
       set yrange [-\ymax:\ymax];
       set view 0,0;
       set isosample 400,400;
       set cont base;
       set cntrparam levels discrete \rangeEP;
       unset surface;
       splot f(x,y)
    };
}
\newcommand{\EVectorOnFieldLines}{ % ELECTRIC FIELD VECTOR
  \message{^^JVector on field lines (\q,\Q) with contours range ^^J\C^^J}
  
  % FIELD LINES
  \path[name path=xline] (\Cx,-\ymax) -- (\Cx,-\a) (\Cx,\a) -- (\Cx,\ymax);
  \path[name path=Elines] plot[id=plot, raw gnuplot, smooth]
    function{
       f(x,y) = \q*(x+\a)/sqrt((x+\a)**2+y**2) + \Q*(x-\a)/sqrt((x-\a)**2+y**2);
       set xrange [\xmin:\xmax];
       set yrange [-\ymax:\ymax];
       set view 0,0;
       set isosample 100,100;
       set cont base;
       set cntrparam levels discrete \C;
       unset surface;
       splot f(x,y)
    };
  
    \message{Intersections...}
    \path[name intersections={of=Elines and xline,total=\t}]
      \pgfextra{\xdef\Nb{\t}};
    \message{ found \Nb ^^J}
    \foreach \i in {1,...,\Nb}{
      \message{  \i}
      \xy{(intersection-\i)}{\xpt}{\ypt}
      \EVector{\xpt}{\ypt}
      \message{ (\D,\x,\y)^^J}
    }
}



\begin{document}


% OPPOSITE, +1 -1
\begin{tikzpicture}
  \def\xmin{-3}
  \def\xmax{3}
  \def\ymax{3}
  \def\a{1}
  \def\q{+1}
  \def\Q{-1}
  \def\R{1.0}
  \def\range{0.05,0.2,0.6,1.0,1.4,1.8,1.98}

  % LINES
  \EFieldLines
  
  % VECTORS
  \def\Cx{-0.4}
  \def\C{0.6,1.0}
  \EVectorOnFieldLines
  \def\Cx{-1.26}
  \EVectorOnFieldLines
  \def\Cx{1.26}
  \EVectorOnFieldLines
  
  % CHARGES
  \draw[charge+] (-\a,0) circle (9pt) node[black,scale=1.0] {$+q$};
  \draw[charge-] (+\a,0) circle (9pt) node[black,scale=1.0] {$-q$};
   
\end{tikzpicture}


%% OPPOSITE, +2 -1
%\begin{tikzpicture}
%  \def\xmin{-3}
%  \def\xmax{3}
%  \def\ymax{3}
%  \def\a{1}
%  \def\q{+2}
%  \def\Q{-1}
%  \def\R{1.0}
%  %\def\range{-2.9,-2.8,-2.6,-2.2,-1.8,-1.4,
%  %           -1.01,-0.6,-0.2,0.2,0.6,0.8,1.0,1.2}
%  \def\range{-0.95,-0.8,-0.6,-0.2,0.2,0.6,
%             1.01,1.4,1.8,2.2,2.6,2.8,2.94}
%
%  % LINES
%  \EFieldLines
%  
%  % CHARGES
%  \draw[charge+] (-\a,0) circle (12pt) node[black,scale=1.0] {$+2q$};
%  \draw[charge-] (+\a,0) circle ( 9pt) node[black,scale=1.0] {$-q$};
%  
%\end{tikzpicture}


%% OPPOSITE, +1 +1
%\begin{tikzpicture}
%  \def\xmin{-3}
%  \def\xmax{3}
%  \def\ymax{3}
%  \def\a{1}
%  \def\q{+1}
%  \def\Q{+1}
%  \def\R{1.2}
%  \def\range{-1.99,-1.8,-1.4,-1.0,-0.6,-0.2,
%             0.2,0.6,1.0,1.4,1.8,1.99}
%  
%  % LINES
%  \EFieldLines
%  
%  % VECTORS
%  \def\Cx{-1.42}
%  \def\C{-1.0}
%  \EVectorOnFieldLines
%  \def\Cx{-0.85}
%  \def\C{-0.6}
%  \EVectorOnFieldLines
%  \fill[Ecol] (0,0) circle (1pt) node[Ecol,above,scale=0.7] {$\mathbf{E}=0$};
%  
%  % CHARGES
%  \draw[charge+] (-\a,0) circle (9pt) node[black,scale=1.0] {$+q$};
%  \draw[charge+] (+\a,0) circle (9pt) node[black,scale=1.0] {$+q$};
%  
%\end{tikzpicture}


%% OPPOSITE, +2 +1 (equipotential surface)
%\begin{tikzpicture}
%  \def\xmin{-3}
%  \def\xmax{3}
%  \def\ymax{3}
%  \def\a{1}
%  \def\q{+2}
%  \def\Q{+1}
%  \def\R{1.2}
%  \def\range{-2.98,-2.7,-2.1,-1.5,-0.9,-0.3,
%              0.3,0.9,1.5,2.1,2.7,2.98}
%
%  % LINES
%  \EFieldLines
%  \fill[Ecol] ({(3-2*sqrt(2))*\a},0) circle (1pt) node[Ecol,above,scale=0.6] {$\mathbf{E}=0$};
%  
%  % CHARGES
%  \draw[charge+] (-\a,0) circle (12pt) node[black,scale=1.0] {$+2q$};
%  \draw[charge+] (+\a,0) circle ( 9pt) node[black,scale=1.0] {$+q$};
%   
%\end{tikzpicture}


%% OPPOSITE, +1 -1 (equipotential surface)
%\begin{tikzpicture}
%  \def\xmin{-3}
%  \def\xmax{3}
%  \def\ymax{3}
%  \def\a{1}
%  \def\q{+1}
%  \def\Q{-1}
%  \def\R{1.0}
%  \def\range{0.05,0.2,0.6,1.0,1.4,1.8,1.98}
%  \def\rangeEP{-1.8,-1.4,-1.0,-0.6,-0.2,0.0,0.2,0.6,1.0,1.4,1.8}
%  
%  % LINES
%  \EFieldLines
%  \EEquipot
%  
%  % CHARGES
%  \draw[charge+] (-\a,0) circle (9pt) node[black,scale=1.0] {$+q$};
%  \draw[charge-] (+\a,0) circle (9pt) node[black,scale=1.0] {$-q$};
%   
%\end{tikzpicture}


%% OPPOSITE, +1 +1 (equipotential surface)
%\begin{tikzpicture}
%  \def\xmin{-3}
%  \def\xmax{3}
%  \def\ymax{3}
%  \def\a{1}
%  \def\q{+1}
%  \def\Q{+1}
%  \def\R{1.2}
%  \def\range{-1.99,-1.8,-1.4,-1.0,-0.6,-0.2,
%             0.2,0.6,1.0,1.4,1.8,1.99}
%  \def\rangeEP{0.0,0.1,0.2,0.4,0.6,0.8,1.0,1.2,1.4,1.6,1.8,2.002,2.2,2.4,2.6}
%  %-1.8,-1.4,-1.0,-0.6,-0.2,
%  
%  % LINES
%  \EFieldLines
%  \EEquipot
%  
%  % CHARGES
%  \draw[charge+] (-\a,0) circle (9pt) node[black,scale=1.0] {$+q$};
%  \draw[charge+] (+\a,0) circle (9pt) node[black,scale=1.0] {$+q$};
%   
%\end{tikzpicture}


\end{document}

Click to download: electric_fieldlines2.texelectric_fieldlines2.pdf
Open in Overleaf: electric_fieldlines2.tex

4 Replies to “Electric field lines of two charges”

  1. Hi
    What a great job on you website !
    There is an issue with this particular template of electric field lines of two charges. Works neither on the web page, nor with overleaf, nor locally.
    Is it possible to get the correct template ?
    many thanks

    1. Hi Ronan,

      Apologies for the late reply, I only saw this comment now.

      I could run the full template locally without problem, but it can take up to 4 min. because the code looks for intersections between the field lines and an ellipse to place the arrows. (Granted, not the most efficient method.)

      Overleaf did not finish the compilation of the full code because it took too long, but if you simply comment out or remove most of the tikzpictures, it should compile the remaining ones within the time limit.

      Compiling on this tikz.net page sady does not work, because gnuplot need to create new files for the field lines, and I think web users do not have writing access to the servers for security reasons.

      Hope that helps!
      Izaak

  2. Hi Izaak
    I tried with Texstudio but it did not work due to an issue of no shape name “intersection-1” is known.
    Thank you for your consideration.
    Best regards,

    1. Hey Duc,
      Sorry for the late reply!
      Did you perhaps run the code after changing something like the contour ranges in \range or the figure size? To place arrowheads on the field lines, the \EFieldLines macro computes intersections with an ellipse or straight line. I guess no intersections were found (\Nb=0), so the foreach “\foreach \i in {1,…,\Nb}” tries to loop from 1 to 0, but “intersection-1” and “intersection-0” do not exist. This might require some finetuning of the contours or ellipse, or you could just remove this snippet in \EFieldLines.
      Cheers,
      Izaak

Leave a Reply

Your email address will not be published.