Source code for ipyforcegraph.sources.dataframe
# Copyright (c) 2023 ipyforcegraph contributors.
# Distributed under the terms of the Modified BSD License.
from typing import Tuple
import ipywidgets as W
import numpy as N
import pandas as P
import traitlets as T
import traittypes as TT
from .._base import ForceBase
from ..serializers import dataframe_serialization
[docs]@W.register
class DataFrameSource(ForceBase):
"""A Graph Source that stores the ``nodes`` and ``links`` as :class:`~pandas.DataFrame` instances."""
_model_name: str = T.Unicode("DataFrameSourceModel").tag(sync=True)
nodes: P.DataFrame = TT.PandasType(
klass=P.DataFrame, help="the :class:`~pandas.DataFrame` of node data"
).tag(sync=True, **dataframe_serialization)
node_id_column: str = T.Unicode(
"id",
help="the name of the column for a node's identifier, or 0-based position in the column if `None`",
).tag(sync=True)
node_preserve_columns: Tuple[str, ...] = W.TypedTuple(
T.Unicode(), help="columns to preserve when updating ``nodes``"
).tag(sync=True)
link_id_column: str = T.Unicode(
"id",
help="the name of the column for a links's identifier, or 0-based position in the column if `None`",
).tag(sync=True)
link_preserve_columns: Tuple[str, ...] = W.TypedTuple(
T.Unicode(), help="columns to preserve when updating ``links``"
).tag(sync=True)
links: P.DataFrame = TT.PandasType(
klass=P.DataFrame, help="the :class:`~pandas.DataFrame` of link data"
).tag(sync=True, **dataframe_serialization)
link_source_column: str = T.Unicode(
"source",
help="the name of the column for a link's source, defaulting to ``source``",
).tag(sync=True)
link_target_column: str = T.Unicode(
"target",
help="the name of the column for a link's target, defaulting to ``target``",
).tag(sync=True)
@T.validate("links")
def _validate_links(self, proposal: T.Bunch) -> P.DataFrame:
value: P.DataFrame = proposal.value
if not isinstance(value, P.DataFrame):
message = f"'links' must be a pandas.DataFrame, not {type(value)}"
raise T.TraitError(message)
if self.link_id_column not in value.columns:
value[self.link_id_column] = N.arange(len(value))
return value
def __repr__(self) -> str:
"""A custom representation to avoid ``pandas``/``numpy`` equality issues."""
name = self.__class__.__name__
nodes_shape = self.nodes.shape if self.nodes is not None else None
links_shape = self.links.shape if self.links is not None else None
return f"{name}(nodes={nodes_shape}, links={links_shape})"