Skip to content

MatFrames Indexer

MetaFrame indexer for accessing MFR (MetaFrame Rows) and MFC (MetaFrame Columns).

The _MfIndexer provides .loc- and .iloc-style access to MetaFrame data (row- and column-level metadata). It is returned when calling obj.mf.loc or obj.mf.iloc.

Access patterns closely mirror pandas indexing semantics but operate on meta-level objects (MFR and MFC) instead of the DataFrame's primary data.

Notes

Valid access formats include:

  • Explicit: obj.mf(i).loc[(mfr_row, mfr_col), (mfc_row, mfc_col)]
  • Regular: obj.mf(i).loc[mfr_col, mfc_col]
  • Valid: obj.mf(i).loc[(mfr_row,), (mfc_row,)]

A single key (obj.mf(i).loc[col] or obj.mf(i).loc[(row, col),] or obj.mf(i).loc[(row,)]) first attempts to resolve as an MFR-based selection; if that fails, it falls back to an MFC-based selection.

When using slices within tuple, they must be explicitly defined as Python slice objects: slice(start, stop) instead of colon notation.

Source code in metaframe/src/indexer/mfindexer.py
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
class _MfIndexer:
    """
    MetaFrame indexer for accessing MFR (MetaFrame Rows) and MFC (MetaFrame Columns).

    The `_MfIndexer` provides `.loc`- and `.iloc`-style access to MetaFrame
    data (row- and column-level metadata). It is returned when calling
    `obj.mf.loc` or `obj.mf.iloc`.

    Access patterns closely mirror pandas indexing semantics but operate on
    meta-level objects (MFR and MFC) instead of the DataFrame's primary data.

    Notes
    -----
    Valid access formats include:

    - **Explicit:** ``obj.mf(i).loc[(mfr_row, mfr_col), (mfc_row, mfc_col)]``
    - **Regular:**  ``obj.mf(i).loc[mfr_col, mfc_col]``
    - **Valid:**    ``obj.mf(i).loc[(mfr_row,), (mfc_row,)]``

    A single key (``obj.mf(i).loc[col]`` or ``obj.mf(i).loc[(row, col),]``
    or ``obj.mf(i).loc[(row,)]``)
    first attempts to resolve as an MFR-based selection; if that fails,
    it falls back to an MFC-based selection.

    When using slices within tuple, they must be explicitly defined as Python 
    `slice` objects: ``slice(start, stop)`` instead of colon notation.
    """

    def __init__(self, df: 'DataFrame', name: Literal["loc", "iloc"]): # type: ignore  # noqa: F821
        self.df = df
        self.name = name

    def __getitem__(self, key: Any) -> 'DataFrame': # type: ignore  # noqa: F821
        """
        Retrieve data from a MetaFrame through `.loc` or `.iloc`.

        Delegates selection to both `mfr` (MetaFrame Rows) and `mfc`
        (MetaFrame Columns), updating the returned DataFrame with the
        relevant metadata based on the provided key(s).

        Parameters
        ----------
        key : object
            A valid loc/iloc indexing expression. Supported forms include:
            - Single key -> tries MFR, then MFC if missing
            - 2-tuple -> (mfr_key, mfc_key)
            - Explicit slices -> only `slice(start, stop)` objects allowed

        Returns
        -------
        DataFrame
            A copy of ``self.df`` updated from the selected MFR/MFC objects.

        Raises
        ------
        Exception
            If an invalid combination of MFR/MFC keys is provided.

        Examples
        --------
        >>> from metaframe.testing import dataframe
        >>> dataframe
        strings             f  g     h
        group               1  0     1
        floats bool  group            
        1.1    False 0      1  A     2
        2.2    False 0      2  B  None
        3.3    True  2      3  C     B
        4.4    True  1      4  D  None
        >>> dataframe.mfloc[([0, 1], ['group', 'bool']), "strings"]
        strings      f  g     h
        group bool             
        0     False  1  A     2
              False  2  B  None
        >>> dataframe.mfiloc[([0, 1], [2, 1]), 0]
        strings      f  g     h
        group bool             
        0     False  1  A     2
              False  2  B  None
        """
        key_mfr, key_mfc = get_inputs_from_key(key, convert_to_list=True)
        mfr_selecter, mfc_selecter = self._get_selecter()
        res = self.df.copy()
        if not is_loc_select_all(key_mfr):
            try:
                res._update_from_mf_obj(mfr_selecter[key_mfr], axis=0, _ignore_id=True)
            except:  # noqa: E722
                if key_mfc is not None:
                    raise
                key_mfc = key_mfr
                key_mfr = None
        if not is_loc_select_all(key_mfc):
            res._update_from_mf_obj(mfc_selecter[key_mfc], axis=1, _ignore_id=True)
        return res

    def __setitem__(self, key: Any, value: Any) -> None:
        """
        Assign values to MetaFrame rows or columns.

        Updates underlying MFR or MFC objects based on the provided key(s),
        propagating changes back into the parent DataFrame.

        Parameters
        ----------
        key : any
            Indexer or tuple specifying the MetaFrame targets to update.
        value : any
            The new value or values to assign.

        Raises
        ------
        ValueError
            If the provided key is incompatible with MetaFrame indexers.

        Examples
        --------
        >>> from metaframe.testing import dataframe
        >>> dataframe
        strings             f  g     h
        group               1  0     1
        floats bool  group            
        1.1    False 0      1  A     2
        2.2    False 0      2  B  None
        3.3    True  2      3  C     B
        4.4    True  1      4  D  None
        >>> dataframe.mfloc['foo'] = 'bar'
        >>> dataframe
        strings                 f  g     h
        group                   1  0     1
        floats bool  group foo            
        1.1    False 0     bar  1  A     2
        2.2    False 0     bar  2  B  None
        3.3    True  2     bar  3  C     B
        4.4    True  1     bar  4  D  None
        >>> dataframe.mfloc[:, "group"] = 2
        >>> dataframe
        strings                 f  g     h
        group                   2  2     2
        floats bool  group foo            
        1.1    False 0     bar  1  A     2
        2.2    False 0     bar  2  B  None
        3.3    True  2     bar  3  C     B
        4.4    True  1     bar  4  D  None
        """
        key_mfr, key_mfc = get_inputs_from_key(key, convert_to_list=False)
        mfr_selecter, mfc_selecter = self._get_selecter()
        if not is_loc_select_all(key_mfr):
            mfr_selecter[key_mfr] = value
            self.df._update_from_mf_obj(mfr_selecter.obj, axis=0)
        if not is_loc_select_all(key_mfc):
            mfc_selecter[key_mfc] = value
            self.df._update_from_mf_obj(mfc_selecter.obj, axis=1, _ignore_id=True)

    def _get_selecter(self) -> Union['_LocIndexer', '_iLocIndexer']: # type: ignore  # noqa: F821
        """
        Retrieve the appropriate indexers for MetaFrame row/column selection.

        Returns
        -------
        list of indexer
            `[mfr.loc, mfc.loc]` if name == "loc",
            `[mfr.iloc, mfc.iloc]` if name == "iloc".
        """
        df = self.df
        if self.name == "loc":
            return [df.mfr.loc, df.mfc.loc]
        return [df.mfr.iloc, df.mfc.iloc]

__getitem__(key)

Retrieve data from a MetaFrame through .loc or .iloc.

Delegates selection to both mfr (MetaFrame Rows) and mfc (MetaFrame Columns), updating the returned DataFrame with the relevant metadata based on the provided key(s).

Parameters:

Name Type Description Default
key object

A valid loc/iloc indexing expression. Supported forms include: - Single key -> tries MFR, then MFC if missing - 2-tuple -> (mfr_key, mfc_key) - Explicit slices -> only slice(start, stop) objects allowed

required

Returns:

Type Description
DataFrame

A copy of self.df updated from the selected MFR/MFC objects.

Raises:

Type Description
Exception

If an invalid combination of MFR/MFC keys is provided.

Examples:

>>> from metaframe.testing import dataframe
>>> dataframe
strings             f  g     h
group               1  0     1
floats bool  group            
1.1    False 0      1  A     2
2.2    False 0      2  B  None
3.3    True  2      3  C     B
4.4    True  1      4  D  None
>>> dataframe.mfloc[([0, 1], ['group', 'bool']), "strings"]
strings      f  g     h
group bool             
0     False  1  A     2
      False  2  B  None
>>> dataframe.mfiloc[([0, 1], [2, 1]), 0]
strings      f  g     h
group bool             
0     False  1  A     2
      False  2  B  None
Source code in metaframe/src/indexer/mfindexer.py
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
def __getitem__(self, key: Any) -> 'DataFrame': # type: ignore  # noqa: F821
    """
    Retrieve data from a MetaFrame through `.loc` or `.iloc`.

    Delegates selection to both `mfr` (MetaFrame Rows) and `mfc`
    (MetaFrame Columns), updating the returned DataFrame with the
    relevant metadata based on the provided key(s).

    Parameters
    ----------
    key : object
        A valid loc/iloc indexing expression. Supported forms include:
        - Single key -> tries MFR, then MFC if missing
        - 2-tuple -> (mfr_key, mfc_key)
        - Explicit slices -> only `slice(start, stop)` objects allowed

    Returns
    -------
    DataFrame
        A copy of ``self.df`` updated from the selected MFR/MFC objects.

    Raises
    ------
    Exception
        If an invalid combination of MFR/MFC keys is provided.

    Examples
    --------
    >>> from metaframe.testing import dataframe
    >>> dataframe
    strings             f  g     h
    group               1  0     1
    floats bool  group            
    1.1    False 0      1  A     2
    2.2    False 0      2  B  None
    3.3    True  2      3  C     B
    4.4    True  1      4  D  None
    >>> dataframe.mfloc[([0, 1], ['group', 'bool']), "strings"]
    strings      f  g     h
    group bool             
    0     False  1  A     2
          False  2  B  None
    >>> dataframe.mfiloc[([0, 1], [2, 1]), 0]
    strings      f  g     h
    group bool             
    0     False  1  A     2
          False  2  B  None
    """
    key_mfr, key_mfc = get_inputs_from_key(key, convert_to_list=True)
    mfr_selecter, mfc_selecter = self._get_selecter()
    res = self.df.copy()
    if not is_loc_select_all(key_mfr):
        try:
            res._update_from_mf_obj(mfr_selecter[key_mfr], axis=0, _ignore_id=True)
        except:  # noqa: E722
            if key_mfc is not None:
                raise
            key_mfc = key_mfr
            key_mfr = None
    if not is_loc_select_all(key_mfc):
        res._update_from_mf_obj(mfc_selecter[key_mfc], axis=1, _ignore_id=True)
    return res

__setitem__(key, value)

Assign values to MetaFrame rows or columns.

Updates underlying MFR or MFC objects based on the provided key(s), propagating changes back into the parent DataFrame.

Parameters:

Name Type Description Default
key any

Indexer or tuple specifying the MetaFrame targets to update.

required
value any

The new value or values to assign.

required

Raises:

Type Description
ValueError

If the provided key is incompatible with MetaFrame indexers.

Examples:

>>> from metaframe.testing import dataframe
>>> dataframe
strings             f  g     h
group               1  0     1
floats bool  group            
1.1    False 0      1  A     2
2.2    False 0      2  B  None
3.3    True  2      3  C     B
4.4    True  1      4  D  None
>>> dataframe.mfloc['foo'] = 'bar'
>>> dataframe
strings                 f  g     h
group                   1  0     1
floats bool  group foo            
1.1    False 0     bar  1  A     2
2.2    False 0     bar  2  B  None
3.3    True  2     bar  3  C     B
4.4    True  1     bar  4  D  None
>>> dataframe.mfloc[:, "group"] = 2
>>> dataframe
strings                 f  g     h
group                   2  2     2
floats bool  group foo            
1.1    False 0     bar  1  A     2
2.2    False 0     bar  2  B  None
3.3    True  2     bar  3  C     B
4.4    True  1     bar  4  D  None
Source code in metaframe/src/indexer/mfindexer.py
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
def __setitem__(self, key: Any, value: Any) -> None:
    """
    Assign values to MetaFrame rows or columns.

    Updates underlying MFR or MFC objects based on the provided key(s),
    propagating changes back into the parent DataFrame.

    Parameters
    ----------
    key : any
        Indexer or tuple specifying the MetaFrame targets to update.
    value : any
        The new value or values to assign.

    Raises
    ------
    ValueError
        If the provided key is incompatible with MetaFrame indexers.

    Examples
    --------
    >>> from metaframe.testing import dataframe
    >>> dataframe
    strings             f  g     h
    group               1  0     1
    floats bool  group            
    1.1    False 0      1  A     2
    2.2    False 0      2  B  None
    3.3    True  2      3  C     B
    4.4    True  1      4  D  None
    >>> dataframe.mfloc['foo'] = 'bar'
    >>> dataframe
    strings                 f  g     h
    group                   1  0     1
    floats bool  group foo            
    1.1    False 0     bar  1  A     2
    2.2    False 0     bar  2  B  None
    3.3    True  2     bar  3  C     B
    4.4    True  1     bar  4  D  None
    >>> dataframe.mfloc[:, "group"] = 2
    >>> dataframe
    strings                 f  g     h
    group                   2  2     2
    floats bool  group foo            
    1.1    False 0     bar  1  A     2
    2.2    False 0     bar  2  B  None
    3.3    True  2     bar  3  C     B
    4.4    True  1     bar  4  D  None
    """
    key_mfr, key_mfc = get_inputs_from_key(key, convert_to_list=False)
    mfr_selecter, mfc_selecter = self._get_selecter()
    if not is_loc_select_all(key_mfr):
        mfr_selecter[key_mfr] = value
        self.df._update_from_mf_obj(mfr_selecter.obj, axis=0)
    if not is_loc_select_all(key_mfc):
        mfc_selecter[key_mfc] = value
        self.df._update_from_mf_obj(mfc_selecter.obj, axis=1, _ignore_id=True)

_get_selecter()

Retrieve the appropriate indexers for MetaFrame row/column selection.

Returns:

Type Description
list of indexer

[mfr.loc, mfc.loc] if name == "loc", [mfr.iloc, mfc.iloc] if name == "iloc".

Source code in metaframe/src/indexer/mfindexer.py
167
168
169
170
171
172
173
174
175
176
177
178
179
180
def _get_selecter(self) -> Union['_LocIndexer', '_iLocIndexer']: # type: ignore  # noqa: F821
    """
    Retrieve the appropriate indexers for MetaFrame row/column selection.

    Returns
    -------
    list of indexer
        `[mfr.loc, mfc.loc]` if name == "loc",
        `[mfr.iloc, mfc.iloc]` if name == "iloc".
    """
    df = self.df
    if self.name == "loc":
        return [df.mfr.loc, df.mfc.loc]
    return [df.mfr.iloc, df.mfc.iloc]