4

I looked at this code:

import numpy as np
from matplotlib import pyplot as plt

def dipole(m, r, r0):
    """
    Calculation of field B in point r. B is created by a dipole moment m located in r0.
    """
# R = r - r0 - subtraction of elements of vectors r and r0, transposition of array
    R = np.subtract(np.transpose(r), r0).T
# Spatial components of r are the outermost axis
    norm_R = np.sqrt(np.einsum("i...,i...", R, R)) # einsum - Einsteinova sumace
# Dot product of R and m
    m_dot_R = np.tensordot(m, R, axes=1)
# Computation of B
    B = 3 * m_dot_R * R / norm_R**5 - np.tensordot(m, 1 / norm_R**3, axes=0)
    B *= 1e-7   # abbreviation for B = B * 1e-7, multiplication B of 1e-7, permeability of vacuum: 4\pi * 10^(-7)
# The result is the magnetic field B
    return B

X = np.linspace(-1, 1)
Y = np.linspace(-1, 1)

Bx, By = dipole(m=[0, 1], r=np.meshgrid(X, Y), r0=[-0.2,0.8])

plt.figure(figsize=(8, 8))
plt.streamplot(X, Y, Bx, By)
plt.margins(0, 0)

plt.show()

It shows the following figure:

enter image description here

Is it possible to get coordinates of one line of force? I don't understand how it is plotted.

Alex
  • 347
  • 1
  • 10
  • One way is to get by clicking mouse on the plot: https://stackoverflow.com/questions/25848951/python-get-mouse-x-y-position-on-click . Or are you looking for printing the coordinates, for which, you would need to know the seed coordinates. – SKPS Feb 17 '20 at 20:22
  • I would like to get a list of coordinates to plot one line from the figure. – Alex Feb 17 '20 at 20:55
  • 1
    Does this answer your question? [How to extract data from matplotlib plot](https://stackoverflow.com/questions/8938449/how-to-extract-data-from-matplotlib-plot) – SKPS Feb 17 '20 at 20:57

1 Answers1

3

The streamplot returns a container object 'StreamplotSet' with two parts:

  • lines: a LineCollection of the streamlines
  • arrows: a PatchCollection containing FancyArrowPatch objects (these are the triangular arrows)

c.lines.get_paths() gives all the segments. Iterating through these segments, their vertices can be examined. When a segment starts where the previous ended, both belong to the same curve. Note that each segment is a short straight line; many segments are used together to form a streamline curve.

The code below demonstrates iterating through the segments. To show what's happening, each segment is converted to an array of 2D points suitable for plt.plot. Default, plt.plot colors each curve with a new color (repeating every 10). The dots show where each of the short straight segments are located.

To find one particular curve, you could hover with the mouse over the starting point, and note the x coordinate of that point. And then test for that coordinate in the code. As an example, the curve that starts near x=0.48 is drawn in a special way.

import numpy as np
from matplotlib import pyplot as plt
from matplotlib import patches

def dipole(m, r, r0):
    R = np.subtract(np.transpose(r), r0).T
    norm_R = np.sqrt(np.einsum("i...,i...", R, R))
    m_dot_R = np.tensordot(m, R, axes=1)
    B = 3 * m_dot_R * R / norm_R**5 - np.tensordot(m, 1 / norm_R**3, axes=0)
    B *= 1e-7
    return B

X = np.linspace(-1, 1)
Y = np.linspace(-1, 1)

Bx, By = dipole(m=[0, 1], r=np.meshgrid(X, Y), r0=[-0.2,0.8])

plt.figure(figsize=(8, 8))
c = plt.streamplot(X, Y, Bx, By)
c.lines.set_visible(False)
paths = c.lines.get_paths()
prev_end = None
start_indices = []
for index, segment in enumerate(paths):
    if not np.array_equal(prev_end, segment.vertices[0]):  # new segment
        start_indices.append(index)
    prev_end = segment.vertices[-1]
for i0, i1 in zip(start_indices, start_indices[1:] + [len(paths)]):
    # get all the points of the curve that starts at index i0
    curve = np.array([paths[i].vertices[0] for i in range(i0, i1)] + [paths[i1 - 1].vertices[-1]])
special_x_coord = 0.48
for i0, i1 in zip(start_indices, start_indices[1:] + [len(paths)]):
    # get all the points of the curve that starts at index i0
    curve = np.array([paths[i].vertices[0] for i in range(i0, i1)] + [paths[i1 - 1].vertices[-1]])
    if abs(curve[0,0] - special_x_coord) < 0.01:  # draw one curve in a special way
        plt.plot(curve[:, 0], curve[:, 1], '-', lw=10, alpha=0.3)
    else:
        plt.plot(curve[:, 0], curve[:, 1], '.', ls='-')

plt.margins(0, 0)
plt.show()

resulting plot

JohanC
  • 71,591
  • 8
  • 33
  • 66
  • Thank you very much. And what does information from `print(c.lines.get_paths()[5])` mean? It gives: `Path(array([[-0.78391976, -0.83498001], [-0.73309273, -0.78981674]]), None)` How to plot it? – Alex Feb 18 '20 at 04:10
  • When I plotted it is a straight line. How to plot a curve? – Alex Feb 18 '20 at 04:16
  • They are all very short line segments. If you want the whole curve, you need to collect all the short segments of one curve (using this test: start of the segment equal to endpoint of the previous segment). If you need something more curved, you could create a splne from these points. – JohanC Feb 18 '20 at 07:50
  • What does splne mean please? Thank you – Alex Feb 18 '20 at 11:41
  • A [spline](https://docs.scipy.org/doc/scipy/reference/tutorial/interpolate.html) can make a smooth interpolation between points. But probably you don't need them, as the segments of the streamplot are already very short. – JohanC Feb 18 '20 at 11:51
  • I'll modify the code to get all curves separated, so you can draw them with `plt.plot`. – JohanC Feb 18 '20 at 11:52
  • Thank you very much. And, for instance, there is the dark blue curve in the right top corner. How to plot only this curve? How to get only these coordinates? – Alex Feb 18 '20 at 17:47
  • Thank you very very much for your help :-) – Alex Feb 18 '20 at 18:38