"""Scalers and unit converters."""
from typing import Optional, Union
from numpy import ndarray
from sklearn.preprocessing import StandardScaler
from neural_data_simulator.tasks.center_out_reach.screen_info import get_monitors
from neural_data_simulator.tasks.center_out_reach.screen_info import get_ppmm
[docs]class PixelsToMetersConverter:
"""Unit conversion between pixels and meters."""
[docs] def __init__(self, ppi: Optional[float]):
"""Initialize the PixelsToMetersConverter class.
Args:
ppi: The pixels per inch of the display or None. If ppi is None, the
function will try to calculate it based on the default monitor.
"""
if ppi is None:
if monitors := get_monitors():
first_monitor = monitors[0]
if ppmm := get_ppmm(first_monitor):
ppi = ppmm[0] * 25.4
if ppi is None:
raise ValueError("Could not detect monitor ppi. Please configure it.")
self.ppi = ppi
self.pixels_per_meter = ppi / 0.0254
self.pixels_per_millimeter = self.pixels_per_meter / 1000
[docs] def pixels_to_millimeters(self, X: ndarray) -> ndarray:
"""Convert pixels to millimeters.
Args:
X: An array of pixel values.
Returns:
The array resulted from the conversion.
"""
return X / self.pixels_per_millimeter
[docs] def millimeters_to_pixels(self, X: ndarray) -> ndarray:
"""Convert millimeters to pixels.
Args:
X: An array of millimeter values.
Returns:
The array resulted from the conversion.
"""
return X * self.pixels_per_millimeter
[docs] def pixels_to_meters(self, X: ndarray) -> ndarray:
"""Convert pixels to meters.
Args:
X: An array of pixel values.
Returns:
The array resulted from the conversion.
"""
return X / self.pixels_per_meter
[docs] def meters_to_pixels(self, X: Union[float, ndarray]) -> Union[float, ndarray]:
"""Convert meters to pixels.
Args:
X: An array of meter values or a single float value.
Returns:
The array resulted from the conversion.
"""
return X * self.pixels_per_meter
[docs]class StandardVelocityScaler:
"""A simple standard scaler for velocities."""
[docs] def __init__(
self, scale: ndarray, mean: ndarray, unit_converter: PixelsToMetersConverter
):
"""Instantiate a new scaler for velocities.
The purpose of this scaler is to scale the velocity to a standard
deviation of 1 and a mean of 0 when calling the transform function.
Args:
scale: The scale to apply to the velocities.
mean: The mean to offset the velocities.
unit_converter: The unit converter to use to convert between
pixels and millimeters.
"""
self.standard_scaler = StandardScaler()
self.standard_scaler.scale_ = scale
self.standard_scaler.mean_ = mean
self.unit_converter = unit_converter