Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 67 additions & 16 deletions examples/example_texture.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@

###############################################################################
# Importation of slam modules
import os
# import os
from pathlib import Path
import numpy as np
from slam import texture
from slam import io as sio
from slam import plot as plt
from slam import plot as proj

###############################################################################
#
Expand All @@ -48,38 +48,89 @@
sio.write_texture(tex2, "test.gii")

#############
print('extremum texture')
mesh = sio.load_mesh("../examples/data/example_mesh.gii")
print('maximum')
print("extremum texture")
print("maximum")
print(np.count_nonzero(tex.extremum(mesh) == 1))
print('minimum')
print("minimum")
print(np.count_nonzero(tex.extremum(mesh) == -1))

###############################################################################
# plot

# dict for proj
# reorient the mesh
mesh.apply_transform(mesh.principal_inertia_transform)
theta = np.pi / 2
rot_x = np.array(
[[1, 0, 0],
[0, np.cos(theta), -np.sin(theta)],
[0, np.sin(theta), np.cos(theta)]]
)
vertices_translate = np.dot(rot_x, mesh.vertices.T).T

# parameters for the projection
# Complete example with all modifiable parameters
NAME_TEX = "sulc"
TITLE = "test"
EXT = "png"
EXT = "html"
PATH = Path("./test")
SAVE_DIR = PATH / f"{TITLE}.{EXT}"

data = tex.darray[0]

mesh_data = {
"vertices": mesh.vertices,
"vertices": vertices_translate,
"faces": mesh.faces,
"center": mesh.center_mass,
"title": TITLE
"title": TITLE, # figure title, default is None
}

intensity_data = {
"values": data,
"mode": "vertex", # default is "cell"
"cmin": 0, # default is automatic value
"cmax": 1,
}

intensity_data = {"values": tex.darray[0], "mode": "vertex"}
display_settings = {"colorscale": "Turbo", "colorbar_label": NAME_TEX}
display_settings = {
"colorscale": "RdBu", # color scale, default is Turbo
"colorbar_label": NAME_TEX, # colorbar label, default is None
"template": "plotly_dark", # default is blank theme without axes
"tickvals": [
0,
0.25,
0.5,
0.75,
1,
], # default is None, sets exact tick positions on the colorbar
"ticktext": [
"0%",
"25%",
"50%",
"75%",
"100%",
], # default is None, customizes tick labels on the colorbar
}

fig = plt.mes3d_projection(
fig = proj.mesh_projection(
mesh_data,
intensity_data,
display_settings,
caption=True, # snapshot, default is None
)

#os.makedirs(PATH, exist_ok=True)
#fig.write_image(SAVE_DIR, width=1600, height=900)
# add an additional trace
# example: display vertex index on hover and customize vertex color and size
# over the mesh
hover_text = [f"vertex {i}" for i in range(len(vertices_translate))]
trace_hover = proj.create_hover_trace(
vertices_translate,
text=hover_text,
marker={"size": 4, "color": "blue"},
)

fig.add_trace(trace_hover, row=1, col=1)
fig.add_trace(trace_hover, row=1, col=2)

# save the figure as an HTML file
# os.makedirs(PATH, exist_ok=True)
# fig.write_html(SAVE_DIR)
# fig.write_image(SAVE_DIR, width=1600, height=900)
9 changes: 0 additions & 9 deletions examples/test.gii

This file was deleted.

178 changes: 110 additions & 68 deletions slam/plot.py
Original file line number Diff line number Diff line change
@@ -1,77 +1,81 @@
"""
plots.py.
plots.py

Centralisation des fonctions pour plots et figures.
Centralized functions for plotting and figures.

Auteur : Zoë LAFFITTE
Date : 2026
Author: Zoë LAFFITTE
Date: 2026
"""

import plotly.graph_objects as go
from plotly.subplots import make_subplots


def create_hover_trace(points, text, mode, **kwargs):
def create_hover_trace(points, text, mode="markers", **kwargs):
"""
Crée une trace 3D pour un graphique Plotly.
Creates a 3D trace for a Plotly figure with customizable options.

Parameters
----------
points : array-like
Coordonnées des points.

labels : array-like
Labels associés aux points.
Coordinates of the points (N, 3).

text : list
Les informations de survol.
Hover information for each point.

mode : str
Mode d'affichage des points (e.g., "markers", "lines").
mode : str, optional
Display mode for the points (e.g., "markers", "lines"),
default is "markers".

**kwargs : dict
Arguments supplémentaires pour personnaliser la trace.
Additional arguments to customize the trace (e.g., marker, hoverlabel).

Returns
-------
plotly.graph_objects.Scatter3d
La trace 3D avec survol.
The 3D trace with hover functionality.
"""

# Création d'une trace 3D avec survol pour chaque point
return go.Scatter3d(
x=points[:, 0],
y=points[:, 1],
z=points[:, 2],
mode=mode,
marker={"size": 1, "color": "rgba(0,0,0,0)"},
text=text,
hoverinfo="text",
showlegend=False,
**kwargs
)


def mes3d_projection(mesh_data, intensity_data=None, display_settings=None):
def mesh_projection(
mesh_data, intensity_data=None, display_settings=None, caption=None
):
"""
Crée une projection 3D d'un maillage, avec ou sans intensités.
Creates a 3D projection of a mesh, with or without intensity data.

Parameters
----------
mesh_data : dict
Contient les coordonnées des sommets et les indices des faces.
Contains the vertex coordinates and face indices of the mesh.

intensity_data : dict, optional
Contient les valeurs d'intensité et le mode d'affichage.
Si None, le maillage est tracé sans texture.
Contains intensity values and display mode.
If None, the mesh is plotted without a texture.

display_settings : dict, optional
Paramètres d'affichage (e.g., colorscale, labels).
Display parameters (e.g., colorscale, labels).

Returns
-------
fig : plotly.graph_objects.Figure
L'objet figure Plotly.
The resulting Plotly figure object.
"""

vertices = mesh_data["vertices"]
faces = mesh_data["faces"]
title = mesh_data.get("title", "")
template = display_settings.get("template", None)

lighting = {
"ambient": 0.7,
Expand All @@ -93,54 +97,92 @@ def mes3d_projection(mesh_data, intensity_data=None, display_settings=None):
"lighting": lighting,
}

if intensity_data is not None:
mesh_kwargs.update({
"intensity": intensity_data["values"],
"intensitymode": intensity_data.get("mode", "cell"),
"colorscale": display_settings.get("colorscale", "Turbo"),
"cmin": intensity_data.get("cmin", None),
"cmax": intensity_data.get("cmax", None),
"colorbar": {
"title": display_settings.get("colorbar_label", ""),
"len": 0.85,
"thickness": 25,
"tickfont": {"size": 16},
},
"flatshading": True,
"lighting": {
"ambient": 1,
"diffuse": 0,
"specular": 0,
"roughness": 1,
"fresnel": 0,
},
"colorbar_tickvals": display_settings.get("tickvals", None),
"colorbar_ticktext": display_settings.get("ticktext", None),
})
camera = dict(
eye=dict(x=2, y=0, z=0), # Camera position from lateral side
center=dict(x=0, y=0, z=0), # Looking at center
up=dict(x=0, y=0, z=1) # Up vector points in positive z direction
)
fig = go.Figure(data=[go.Mesh3d(**mesh_kwargs)])

fig.update_layout(
title=title,
title_x=0.2,
template="seaborn",
scene=dict(
aspectmode="data",
xaxis=dict(visible=False),
yaxis=dict(visible=False),
zaxis=dict(visible=False),
camera=camera
),
legend={
camera = {
# Camera position from lateral side
"eye": {"x": 2.5, "y": 0, "z": 0.0},
# Looking at center
"center": {"x": 0, "y": 0, "z": 0},
# Up vector points in positive z direction
"up": {"x": 0, "y": 0, "z": 1},
}

aff_dict = {
"title": title,
"title_x": 0.2,
"height": 900,
"width": 1200,
"template": template,
"legend": {
"x": 0,
"y": 1,
"xanchor": "left",
"yanchor": "top",
},
)
"scene": {"camera": camera},
}

if intensity_data is not None:
mesh_kwargs.update(
{
"intensity": intensity_data["values"],
"intensitymode": intensity_data.get("mode", "cell"),
"colorscale": display_settings.get("colorscale", "Turbo"),
"cmin": intensity_data.get("cmin", None),
"cmax": intensity_data.get("cmax", None),
"colorbar": {
"title": display_settings.get("colorbar_label", ""),
"len": 0.85,
"thickness": 25,
"tickfont": {"size": 16},
},
"flatshading": True,
"lighting": {
"ambient": 1,
"diffuse": 0,
"specular": 0,
"roughness": 1,
"fresnel": 0,
},
"colorbar_tickvals": display_settings.get("tickvals", None),
"colorbar_ticktext": display_settings.get("ticktext", None),
}
)

if caption:
fig = make_subplots(
rows=1,
cols=2,
specs=[[{"type": "scene"}, {"type": "scene"}]],
horizontal_spacing=0.03,
)
for col in [1, 2]:
fig.add_trace(go.Mesh3d(**mesh_kwargs), row=1, col=col)

aff_dict["scene2"] = {
"camera": {
# Camera position from lateral side
"eye": {"x": -2.5, "y": 0, "z": 0.0},
# Looking at center
"center": {"x": 0, "y": 0, "z": 0},
# Up vector points in positive z direction
"up": {"x": 0, "y": 0, "z": 1},
}
}

else:
fig = go.Figure(data=[go.Mesh3d(**mesh_kwargs)])

if template is None:
aff_dict["template"] = "simple_white"
aff_dict["scene"].update(
{
"aspectmode": "data",
"xaxis": {"visible": False},
"yaxis": {"visible": False},
"zaxis": {"visible": False},
}
)

fig.update_layout(**aff_dict)

return fig
Loading