Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Reference spaces #809

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

Draft
wants to merge 4 commits into
base: main
Choose a base branch
Loading
from
Draft
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
59 changes: 59 additions & 0 deletions 59 examples/reference_spaces/line_scales.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import numpy as np
import fastplotlib as fpl
from fastplotlib.ui import DebugWindow
import pygfx
from icecream import ic

xs = np.linspace(0, 10 * np.pi, 1000)
ys = np.sin(xs)

ys100 = ys * 1000

l1 = np.column_stack([xs, ys])
l2 = np.column_stack([xs, ys100])

fig = fpl.Figure(size=(500, 400))

fig[0, 0].add_line(l1)
fig.show(maintain_aspect=False)
fig[0, 0].auto_scale(zoom=0.4)

rs = fig[0, 0].add_reference_frame(
scale=(1, 500, 1),
)
l2 = fig[0, 0].add_line(l2, reference_space=rs, colors="r")
l2.add_axes(rs)
l2.axes.y.line.material.color = "m"


@fig.renderer.add_event_handler("key_down")
def change_y_scale(ev: pygfx.KeyboardEvent):
if ev.key != "1":
return

rs.controller.remove_camera(rs.camera)
rs.controller.add_camera(rs.camera, include_state={"height"})

fig[0, 0].controller.enabled = False


@fig.renderer.add_event_handler("key_down")
def change_y_scale(ev: pygfx.KeyboardEvent):
if ev.key != "0":
return

rs.controller.remove_camera(rs.camera)
rs.controller.add_camera(rs.camera)
fig[0, 0].controller.enabled = True


debug_objs = [
fig[0, 0].camera.get_state,
rs.camera.get_state
]

debug_window = DebugWindow(debug_objs)
fig.add_gui(debug_window)


fpl.loop.run()
48 changes: 24 additions & 24 deletions 48 fastplotlib/graphics/_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ def yz(self) -> Grid:
class Axes:
def __init__(
self,
plot_area,
reference_space,
intersection: tuple[int, int, int] | None = None,
x_kwargs: dict = None,
y_kwargs: dict = None,
Expand All @@ -157,7 +157,7 @@ def __init__(
[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]
),
):
self._plot_area = plot_area
self._reference_space = reference_space

if x_kwargs is None:
x_kwargs = dict()
Expand Down Expand Up @@ -193,20 +193,20 @@ def __init__(
self.x.end_pos = 100, 0, 0
self.x.start_value = self.x.start_pos[0] - offset[0]
statsx = self.x.update(
self._plot_area.camera, self._plot_area.viewport.logical_size
self._reference_space.camera, self._reference_space.viewport.logical_size
)

self.y.start_pos = 0, 0, 0
self.y.end_pos = 0, 100, 0
self.y.start_value = self.y.start_pos[1] - offset[1]
statsy = self.y.update(
self._plot_area.camera, self._plot_area.viewport.logical_size
self._reference_space.camera, self._reference_space.viewport.logical_size
)

self.z.start_pos = 0, 0, 0
self.z.end_pos = 0, 0, 100
self.z.start_value = self.z.start_pos[1] - offset[2]
self.z.update(self._plot_area.camera, self._plot_area.viewport.logical_size)
self.z.update(self._reference_space.camera, self._reference_space.viewport.logical_size)

# world object for the rulers + grids
self._world_object = pygfx.Group()
Expand All @@ -219,7 +219,7 @@ def __init__(
)

# set z ruler invisible for orthographic projections for now
if self._plot_area.camera.fov == 0:
if self._reference_space.camera.fov == 0:
# TODO: allow any orientation in the future even for orthographic projections
self.z.visible = False

Expand Down Expand Up @@ -251,7 +251,7 @@ def __init__(
self._grids = Grids(**_grids)
self.world_object.add(self._grids)

if self._plot_area.camera.fov == 0:
if self._reference_space.camera.fov == 0:
# orthographic projection, place grids far away
self._grids.local.z = -1000

Expand Down Expand Up @@ -382,13 +382,13 @@ def update_using_bbox(self, bbox):
"""

# flip axes if camera scale is flipped
if self._plot_area.camera.local.scale_x < 0:
if self._reference_space.camera.local.scale_x < 0:
bbox[0, 0], bbox[1, 0] = bbox[1, 0], bbox[0, 0]

if self._plot_area.camera.local.scale_y < 0:
if self._reference_space.camera.local.scale_y < 0:
bbox[0, 1], bbox[1, 1] = bbox[1, 1], bbox[0, 1]

if self._plot_area.camera.local.scale_z < 0:
if self._reference_space.camera.local.scale_z < 0:
bbox[0, 2], bbox[1, 2] = bbox[1, 2], bbox[0, 2]

if self.intersection is None:
Expand All @@ -413,8 +413,8 @@ def update_using_camera(self):
if not self.visible:
return

if self._plot_area.camera.fov == 0:
xpos, ypos, width, height = self._plot_area.viewport.rect
if self._reference_space.camera.fov == 0:
xpos, ypos, width, height = self._reference_space.viewport.rect
# orthographic projection, get ranges using inverse

# get range of screen space by getting the corners
Expand Down Expand Up @@ -442,8 +442,8 @@ def update_using_camera(self):
# self.y.local.rotation
# )

min_vals = self._plot_area.map_screen_to_world((xmin, ymin))
max_vals = self._plot_area.map_screen_to_world((xmax, ymax))
min_vals = self._reference_space.map_screen_to_world((xmin, ymin))
max_vals = self._reference_space.map_screen_to_world((xmax, ymax))

if min_vals is None or max_vals is None:
return
Expand All @@ -462,14 +462,14 @@ def update_using_camera(self):

else:
# set ruler start and end positions based on scene bbox
bbox = self._plot_area._fpl_graphics_scene.get_world_bounding_box()
bbox = self._reference_space._fpl_graphics_scene.get_world_bounding_box()

if self.intersection is None:
if self._plot_area.camera.fov == 0:
if self._reference_space.camera.fov == 0:
# place the ruler close to the left and bottom edges of the viewport
# TODO: determine this for perspective projections
xscreen_10, yscreen_10 = xpos + (width * 0.1), ypos + (height * 0.9)
intersection = self._plot_area.map_screen_to_world(
intersection = self._reference_space.map_screen_to_world(
(xscreen_10, yscreen_10)
)
else:
Expand Down Expand Up @@ -502,15 +502,15 @@ def update(self, bbox, intersection):
world_x_10, world_y_10, world_z_10 = intersection

# swap min and max for each dimension if necessary
if self._plot_area.camera.local.scale_y < 0:
if self._reference_space.camera.local.scale_y < 0:
world_ymin, world_ymax = world_ymax, world_ymin
self.y.tick_side = "right" # swap tick side
self.x.tick_side = "right"
else:
self.y.tick_side = "left"
self.x.tick_side = "right"

if self._plot_area.camera.local.scale_x < 0:
if self._reference_space.camera.local.scale_x < 0:
world_xmin, world_xmax = world_xmax, world_xmin
self.x.tick_side = "left"

Expand All @@ -519,24 +519,24 @@ def update(self, bbox, intersection):

self.x.start_value = self.x.start_pos[0] - self.offset[0]
statsx = self.x.update(
self._plot_area.camera, self._plot_area.viewport.logical_size
self._reference_space.camera, self._reference_space.viewport.logical_size
)

self.y.start_pos = world_x_10, world_ymin, world_z_10
self.y.end_pos = world_x_10, world_ymax, world_z_10

self.y.start_value = self.y.start_pos[1] - self.offset[1]
statsy = self.y.update(
self._plot_area.camera, self._plot_area.viewport.logical_size
self._reference_space.camera, self._reference_space.viewport.logical_size
)

if self._plot_area.camera.fov != 0:
if self._reference_space.camera.fov != 0:
self.z.start_pos = world_x_10, world_y_10, world_zmin
self.z.end_pos = world_x_10, world_y_10, world_zmax

self.z.start_value = self.z.start_pos[2] - self.offset[2]
statsz = self.z.update(
self._plot_area.camera, self._plot_area.viewport.logical_size
self._reference_space.camera, self._reference_space.viewport.logical_size
)
major_step_z = statsz["tick_step"]

Expand All @@ -546,7 +546,7 @@ def update(self, bbox, intersection):
self.grids.xy.major_step = major_step_x, major_step_y
self.grids.xy.minor_step = 0.2 * major_step_x, 0.2 * major_step_y

if self._plot_area.camera.fov != 0:
if self._reference_space.camera.fov != 0:
self.grids.xz.major_step = major_step_x, major_step_z
self.grids.xz.minor_step = 0.2 * major_step_x, 0.2 * major_step_z

Expand Down
6 changes: 3 additions & 3 deletions 6 fastplotlib/graphics/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -447,15 +447,15 @@ def rotate(self, alpha: float, axis: Literal["x", "y", "z"] = "y"):
def axes(self) -> Axes:
return self._axes

def add_axes(self):
def add_axes(self, reference_frame):
"""Add axes onto this Graphic"""
if self._axes is not None:
raise AttributeError("Axes already added onto this graphic")

self._axes = Axes(self._plot_area, offset=self.offset, grids=False)
self._axes = Axes(reference_frame, offset=self.offset, grids=False)
self._axes.world_object.local.rotation = self.world_object.local.rotation

self._plot_area.scene.add(self.axes.world_object)
reference_frame.scene.add(self.axes.world_object)
self._axes.update_using_bbox(self.world_object.get_world_bounding_box())

@property
Expand Down
31 changes: 18 additions & 13 deletions 31 fastplotlib/layouts/_graphic_methods_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,16 @@ def _create_graphic(self, graphic_class, *args, **kwargs) -> Graphic:
else:
center = False

if "reference_space" in kwargs.keys():
reference_space = kwargs.pop("reference_space")
else:
reference_space = 0

if "name" in kwargs.keys():
self._check_graphic_name_exists(kwargs["name"])

graphic = graphic_class(*args, **kwargs)
self.add_graphic(graphic, center=center)
self.add_graphic(graphic, center=center, reference_space=reference_space)

return graphic

Expand All @@ -32,7 +37,7 @@ def add_image(
interpolation: str = "nearest",
cmap_interpolation: str = "linear",
isolated_buffer: bool = True,
**kwargs,
**kwargs
) -> ImageGraphic:
"""

Expand Down Expand Up @@ -78,7 +83,7 @@ def add_image(
interpolation,
cmap_interpolation,
isolated_buffer,
**kwargs,
**kwargs
)

def add_line_collection(
Expand All @@ -96,7 +101,7 @@ def add_line_collection(
metadatas: Union[Sequence[Any], numpy.ndarray] = None,
isolated_buffer: bool = True,
kwargs_lines: list[dict] = None,
**kwargs,
**kwargs
) -> LineCollection:
"""

Expand Down Expand Up @@ -169,7 +174,7 @@ def add_line_collection(
metadatas,
isolated_buffer,
kwargs_lines,
**kwargs,
**kwargs
)

def add_line(
Expand All @@ -183,7 +188,7 @@ def add_line(
cmap_transform: Union[numpy.ndarray, Iterable] = None,
isolated_buffer: bool = True,
size_space: str = "screen",
**kwargs,
**kwargs
) -> LineGraphic:
"""

Expand Down Expand Up @@ -234,7 +239,7 @@ def add_line(
cmap_transform,
isolated_buffer,
size_space,
**kwargs,
**kwargs
)

def add_line_stack(
Expand All @@ -253,7 +258,7 @@ def add_line_stack(
separation: float = 10.0,
separation_axis: str = "y",
kwargs_lines: list[dict] = None,
**kwargs,
**kwargs
) -> LineStack:
"""

Expand Down Expand Up @@ -334,7 +339,7 @@ def add_line_stack(
separation,
separation_axis,
kwargs_lines,
**kwargs,
**kwargs
)

def add_scatter(
Expand All @@ -349,7 +354,7 @@ def add_scatter(
sizes: Union[float, numpy.ndarray, Iterable[float]] = 1,
uniform_size: bool = False,
size_space: str = "screen",
**kwargs,
**kwargs
) -> ScatterGraphic:
"""

Expand Down Expand Up @@ -409,7 +414,7 @@ def add_scatter(
sizes,
uniform_size,
size_space,
**kwargs,
**kwargs
)

def add_text(
Expand All @@ -422,7 +427,7 @@ def add_text(
screen_space: bool = True,
offset: tuple[float] = (0, 0, 0),
anchor: str = "middle-center",
**kwargs,
**kwargs
) -> TextGraphic:
"""

Expand Down Expand Up @@ -473,5 +478,5 @@ def add_text(
screen_space,
offset,
anchor,
**kwargs,
**kwargs
)
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.