diff --git a/octarine/utils.py b/octarine/utils.py index a57ce29..8b3a225 100644 --- a/octarine/utils.py +++ b/octarine/utils.py @@ -2,7 +2,6 @@ import pygfx as gfx import numpy as np -import pandas as pd from collections.abc import Iterable @@ -46,7 +45,7 @@ def parse_objects(x, include_geometries=True): scatter = [ob for ob in x if isinstance(ob, np.ndarray) and (ob.ndim == 2) and (ob.shape[1] == 3)] # Collect dataframes with X/Y/Z coordinates - dataframes = [ob for ob in x if isinstance(ob, pd.DataFrame)] + dataframes = [ob for ob in x if _is_pandas_dataframe(ob)] if [d for d in dataframes if False in np.isin(['x', 'y', 'z'], d.columns)]: logger.warning('DataFrames must have x, y and z columns.') dataframes = [d for d in dataframes if all(np.isin(['x', 'y', 'z'], d.columns))] @@ -58,14 +57,6 @@ def parse_objects(x, include_geometries=True): # Collect meshes meshes = [ob for ob in x if is_mesh_like(ob)] - # Collect dataframes with X/Y/Z coordinates - dataframes = [ob for ob in x if isinstance(ob, pd.DataFrame)] - if [d for d in dataframes if False in np.isin(['x', 'y', 'z'], d.columns)]: - logger.warning('DataFrames must have x, y and z columns.') - # Filter to and extract x/y/z coordinates - dataframes = [d for d in dataframes if False not in [c in d.columns for c in ['x', 'y', 'z']]] - dataframes = [d[['x', 'y', 'z']].values for d in dataframes] - # Collect arrays arrays = [ob.copy() for ob in x if isinstance(ob, np.ndarray)] # Remove arrays with wrong dimensions @@ -79,6 +70,19 @@ def parse_objects(x, include_geometries=True): return meshes, volumes, points, visuals +def _is_pandas_dataframe(x): + """Check if object is a pandas DataFrame.""" + # We're doing this without the use of isinstance() to avoid + # needing pandas as a dependency + if not hasattr(x, "__class__"): + return False + # Check if any of the parent classes is a pandas DataFrame + for b in x.__class__.__mro__: + if b.__module__.startswith("pandas") and b.__name__ == "DataFrame": + return True + return False + + def make_iterable(x, force_type = None): """Force input into a numpy array. @@ -118,7 +122,7 @@ def is_iterable(x) -> bool: True """ - if isinstance(x, Iterable) and not isinstance(x, (six.string_types, pd.DataFrame)): + if isinstance(x, Iterable) and not isinstance(x, six.string_types) and not _is_pandas_dataframe(x): return True else: return False diff --git a/requirements.txt b/requirements.txt index 539ff21..d38e47b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,5 @@ pygfx>=0.2.0 numpy -pandas pypng six cmap