Spin-plotting routine (3D)

Here you will find a pre-defined function that can plot the set of spin directions from vampire's output file as a 3D plot.

Definition of the plotting function

Execute the cell below to have the function defined

import wulfric
import numpy as np
from tqdm import tqdm
import matplotlib


def plot_spins(
    filename,
    skip_spins=100,
    scale=2.0,
    color_mode="z",
    color_projection=None,
    colormap="bwr",
    vmin=None,
    vmax=None,
    spin_origin=0.5,
    xrange=None,
    yrange=None,
    zrange=None,
):
    # Check spin origin
    if not 0 <= spin_origin <= 1:
        raise ValueError(
            f"Misplaced spin origin, Expected 0 <= spin_origin <= 1, got {spin_origin}."
        )

    # Load data
    data = np.loadtxt(filename, skiprows=1)

    # Get cmap
    cmap = matplotlib.colormaps[colormap]

    # Skip some spins
    orig_shape = data.shape
    data = data[::skip_spins]

    print(
        f"Got {orig_shape[0]} spins, using every {skip_spins} ({data.shape[0]} spins in total)"
    )

    # Make a cut if needded
    if xrange is not None:
        data = data[xrange[0] <= data[:, 0]]
        data = data[data[:, 0] <= xrange[1]]
    if yrange is not None:
        data = data[yrange[0] <= data[:, 1]]
        data = data[data[:, 1] <= yrange[1]]
    if zrange is not None:
        data = data[zrange[0] <= data[:, 2]]
        data = data[data[:, 2] <= zrange[1]]

    print(f"Plotting {data.shape[0]} spins after the real-space cut")

    # Compute color values
    if color_mode == "z":
        color_projection = [0.0, 0.0, 1.0]
    elif color_mode == "y":
        color_projection = [0.0, 1.0, 0.0]
    elif color_mode == "x":
        color_projection = [1.0, 0.0, 0.0]
    elif color_mode == "projection":
        if color_projection is None:
            raise ValueError(
                f"Expected vector for color_projection, got '{color_projection}'"
            )
    else:
        raise ValueError(
            f"Expected 'z', 'y', 'x' or 'projection' for color_mode, got '{color_mode}'"
        )
    color_projection = color_projection / np.linalg.norm(color_projection)
    colors_values = data[:, 3:] @ color_projection

    # Get the normalizer for color values
    if vmin is None:
        vmin = colors_values.min()
    if vmax is None:
        vmax = colors_values.max()
    norm = matplotlib.colors.Normalize(vmin=vmin, vmax=vmax)

    # Scale spin vectors
    data[:, 3:] = data[:, 3:] * scale * 20

    # Plot all vectors
    pe = wulfric.PlotlyEngine(_sphinx_gallery_fix=True)
    for i, (x, y, z, sx, sy, sz) in enumerate(tqdm(data)):
        pe.plot_vector(
            start_point=[
                x - spin_origin * sx,
                y - spin_origin * sy,
                z - spin_origin * sz,
            ],
            end_point=[
                x + (1 - spin_origin) * sx,
                y + (1 - spin_origin) * sy,
                z + (1 - spin_origin) * sz,
            ],
            color=matplotlib.colors.rgb2hex(cmap(norm(colors_values[i]))),
        )

    print("All spins are processed, starting to show the plot ...")
    print("Hint: zoom out in the plot if necessary.")

    # Change from default camera position
    camera = dict(
        up=dict(x=0, y=0, z=1),
        center=dict(
            x=np.mean(data[:, 0]), y=np.mean(data[:, 1]), z=np.mean(data[:, 2])
        ),
        eye=dict(x=data[:, 0].min(), y=data[:, 1].min(), z=2),
    )

    pe.fig.update_layout(scene_camera=camera)

    # Show the plot
    return pe.show(width=1000, height=1000)

Explanation for the parameters

You have to provide one parameter

  • filename : str

    Name of the file with spin positions and directions.

Other parameters are optional. They control the appearance of the plot:

  • skip_spins : int, default 100

    There is a lot of spins in the output file, to make the plot responsive one need to plot only every Nth spin. This option sets that number N.

  • scale : float, default 1.0

    This parameter controls the scale of the spin vectors length, play with this value for better-looking result. Increase to make spin vectors appear longer.

  • color_mode : str, default "z"

    What value to use for coloring of the spins. Supported:

    • "z" - use z components

    • "y" - use y components

    • "x" - use x components

    • "projection" - use projection along color_projection.

  • color_projection : (3,) array-like

    Direction for the spin projection to use for coloring. Used if color_mode = "projection".

  • colormap : str, default "bwr"

    Any colormap supported by matplotlib. See https://matplotlib.org/stable/users/explain/colors/colormaps.html for supported names.

  • vmin : float, optional

    min value for color value normalization.

  • vmax : float, optional

    max value for color value normalization.

  • spin_origin : float, default 0.5

    Where shall spin vector start. If 0, then position is at the begining of the vector, if 0.5 - then position is in the middle of the vector, if 1 - then position is at the end of the vector.

  • xrange : tuple of 2 float

    Specifies the real-space range on the graph that is plotted. Use it to cut the regions that you want to plot.

  • yrange : tuple of 2 float

    Specifies the real-space range on the graph that is plotted. Use it to cut the regions that you want to plot.

  • zrange : tuple of 2 float

    Specifies the real-space range on the graph that is plotted. Use it to cut the regions that you want to plot.

Plot with all values set to defaults.

plot_spins("spins-00000020.txt")
Got 12108 spins, using every 100 (122 spins in total)
Plotting 122 spins after the real-space cut

  0%|          | 0/122 [00:00<?, ?it/s]
 67%|██████▋   | 82/122 [00:00<00:00, 818.92it/s]
100%|██████████| 122/122 [00:00<00:00, 878.13it/s]
All spins are processed, starting to show the plot ...
Hint: zoom out in the plot if necessary.


Plot a real-space cut with all spins in this region (i.e. skipping none) and reduced visible spin vector length

plot_spins(
    "spins-00000020.txt", xrange=(-20, 20), yrange=(-20, 20), skip_spins=1, scale=0.1
)
Got 12108 spins, using every 1 (12108 spins in total)
Plotting 71 spins after the real-space cut

  0%|          | 0/71 [00:00<?, ?it/s]
 89%|████████▊ | 63/71 [00:00<00:00, 612.05it/s]
100%|██████████| 71/71 [00:00<00:00, 628.13it/s]
All spins are processed, starting to show the plot ...
Hint: zoom out in the plot if necessary.


Same as before, but coloring according to the value of s_y

plot_spins(
    "spins-00000020.txt",
    xrange=(-20, 20),
    yrange=(-20, 20),
    skip_spins=1,
    scale=0.1,
    color_mode="y",
)
Got 12108 spins, using every 1 (12108 spins in total)
Plotting 71 spins after the real-space cut

  0%|          | 0/71 [00:00<?, ?it/s]
 83%|████████▎ | 59/71 [00:00<00:00, 585.58it/s]
100%|██████████| 71/71 [00:00<00:00, 435.28it/s]
All spins are processed, starting to show the plot ...
Hint: zoom out in the plot if necessary.


Total running time of the script: (0 minutes 0.743 seconds)

Gallery generated by Sphinx-Gallery