Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve extra model3d to accommodate positional arguments in plotting function #431

Merged
merged 6 commits into from Dec 20, 2021

Conversation

Alexboiboi
Copy link
Member

@Alexboiboi Alexboiboi commented Dec 19, 2021

Some matplotlib functions such as plot_trisurf only allow coordinates to be provided via positional arguments. When providing an extra model3d, one needs a way to provide such arguments via a dictionary while allowing the magpylib library take care of the positioning and orienting of the provied trace.
This is useful if we want to provide a complex model originating from a CAD model and plot it with the magpylib display function. For example a complex mesh object representing a 3d-model of sensor can be attached to a magpylib sensor and moved automatically with it.

import os
import tempfile

import magpylib as magpy
import numpy as np
import plotly.graph_objects as go
import requests
from stl import mesh  # needs numpy-stl installed

def get_stl_color(x, return_rgb_string=True):
    sb = f"{x:015b}"[::-1]
    r = int(255 / 31 * int(sb[:5], base=2))
    g = int(255 / 31 * int(sb[5:10], base=2))
    b = int(255 / 31 * int(sb[10:15], base=2))
    if return_rgb_string:
        color = f'rgb({r},{g},{b})'
    else:
        color = (r,g,b)
    return color

# define stl to mesh3d function
def stl2mesh3d(stl_file, recenter=False, backend='matplotlib'):
    stl_mesh = mesh.Mesh.from_file(stl_file)
    # stl_mesh is read by nympy-stl from a stl file; it is  an array of faces/triangles
    # this function extracts the unique vertices and the lists I, J, K to define a Plotly mesh3d
    p, q, r = stl_mesh.vectors.shape  # (p, 3, 3)
    # the array stl_mesh.vectors.reshape(p*q, r) can contain multiple copies of the same vertex;
    # extract unique vertices from all mesh triangles
    vertices, ixr = np.unique(
        stl_mesh.vectors.reshape(p * q, r), return_inverse=True, axis=0
    )
    i = np.take(ixr, [3 * k for k in range(p)])
    j = np.take(ixr, [3 * k + 1 for k in range(p)])
    k = np.take(ixr, [3 * k + 2 for k in range(p)])
    if recenter:
        vertices = vertices - 0.5 * (vertices.max(axis=0) + vertices.min(axis=0))
    colors = stl_mesh.attr.flatten()
    x, y, z = vertices.T
    model3d = {"backend": backend}
    if backend == "matplotlib":
        triangles = np.array([i, j, k]).T
        model3d.update(
            trace=dict(type="plot_trisurf", args=(x, y, z), triangles=triangles),
            coordsargs={"x": "args[0]", "y": "args[1]", "z": "args[2]"},
        )
    elif backend == "plotly":
        facecolor = np.array([get_stl_color(x, return_rgb_string=True) for x in colors]).T
        model3d.update(
            trace=dict(
                type="mesh3d", x=x, y=y, z=z, i=i, j=j, k=k, facecolor=facecolor
            ),
        )
    else:
        raise ValueError(
            """Backend type not understood, must be one of ['matplotlib', 'plotly']"""
        )
    return model3d


# import stl file
url = "https://raw.githubusercontent.com/magpylib/magpylib-files/main/PG-SSO-3-2.stl"
file = url.split("/")[-1]
with tempfile.TemporaryDirectory() as tmpdirname:
    fn = os.path.join(tmpdirname, file)
    with open(fn, "wb") as f:
        response = requests.get(url)
        f.write(response.content)

    # create mesh3d
    model3d_matplotlib = stl2mesh3d(fn, backend="matplotlib")
    model3d_plotly = stl2mesh3d(fn, backend="plotly")
# create sensor, add extra 3d-model, create path
sensor = magpy.Sensor(position=(-15, 0, -6))
sensor.style = dict(model3d_extra=[model3d_matplotlib, model3d_plotly])
sensor.rotate_from_angax([5] * 30, "z", increment=True, anchor=(0, 0, 0))
sensor.move([[0, 0, 0.5]] * 30, increment=True, start=0)

# create source, and Collection
cuboid = magpy.magnet.Cylinder(magnetization=(0, 0, 1000), dimension=(20, 30))
collection = sensor + cuboid

# display animated system with plotly backend
magpy.display(collection, path=8, style_magnetization_size=0.4, backend="matplotlib")
magpy.display(collection, path=8, backend="plotly")

image

image

@Alexboiboi Alexboiboi added the bug needs attention label Dec 19, 2021
@Alexboiboi Alexboiboi self-assigned this Dec 19, 2021
@Alexboiboi Alexboiboi modified the milestones: 4.1, 4.0 Dec 19, 2021
@codecov-commenter
Copy link

Codecov Report

Merging #431 (060d435) into development (212918b) will increase coverage by 0.00%.
The diff coverage is 100.00%.

Impacted file tree graph

@@             Coverage Diff              @@
##           development     #431   +/-   ##
============================================
  Coverage        99.74%   99.74%           
============================================
  Files               46       46           
  Lines             4735     4764   +29     
============================================
+ Hits              4723     4752   +29     
  Misses              12       12           
Impacted Files Coverage Δ
magpylib/_src/display/disp_utility.py 100.00% <100.00%> (ø)
magpylib/_src/display/mpl_draw.py 100.00% <100.00%> (ø)
magpylib/_src/style.py 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 212918b...060d435. Read the comment docs.

@Alexboiboi Alexboiboi marked this pull request as ready for review December 20, 2021 15:44
@Alexboiboi Alexboiboi merged commit 4067f22 into development Dec 20, 2021
@Alexboiboi Alexboiboi deleted the model3dfix branch December 20, 2021 16:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug needs attention graphics
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants