Create a new Pandas MultiIndex from the product of 1-d variables (levels) along a new dimension. Level variables must have a dimension distinct from each other. Keeps levels the same (doesn't refactorize them) so that it gives back the original labels after a stack/
(
cls, variables: Mapping[Any, Variable], dim: Hashable
)
| 1101 | |
| 1102 | @classmethod |
| 1103 | def stack( |
| 1104 | cls, variables: Mapping[Any, Variable], dim: Hashable |
| 1105 | ) -> PandasMultiIndex: |
| 1106 | """Create a new Pandas MultiIndex from the product of 1-d variables (levels) along a |
| 1107 | new dimension. |
| 1108 | |
| 1109 | Level variables must have a dimension distinct from each other. |
| 1110 | |
| 1111 | Keeps levels the same (doesn't refactorize them) so that it gives back the original |
| 1112 | labels after a stack/unstack roundtrip. |
| 1113 | |
| 1114 | """ |
| 1115 | _check_dim_compat(variables, all_dims="different") |
| 1116 | |
| 1117 | level_indexes = [safe_cast_to_index(var) for var in variables.values()] |
| 1118 | for name, idx in zip(variables, level_indexes, strict=True): |
| 1119 | if isinstance(idx, pd.MultiIndex): |
| 1120 | raise ValueError( |
| 1121 | f"cannot create a multi-index along stacked dimension {dim!r} " |
| 1122 | f"from variable {name!r} that wraps a multi-index" |
| 1123 | ) |
| 1124 | |
| 1125 | # from_product sorts by default, so we can't use that always |
| 1126 | # https://github.com/pydata/xarray/issues/980 |
| 1127 | # https://github.com/pandas-dev/pandas/issues/14672 |
| 1128 | if all(index.is_monotonic_increasing for index in level_indexes): |
| 1129 | index = pd.MultiIndex.from_product( |
| 1130 | level_indexes, sortorder=0, names=list(variables.keys()) |
| 1131 | ) |
| 1132 | else: |
| 1133 | split_labels, levels = zip( |
| 1134 | *[lev.factorize() for lev in level_indexes], strict=True |
| 1135 | ) |
| 1136 | labels_mesh = np.meshgrid(*split_labels, indexing="ij") |
| 1137 | labels = [x.ravel().tolist() for x in labels_mesh] |
| 1138 | |
| 1139 | index = pd.MultiIndex( |
| 1140 | levels=levels, codes=labels, sortorder=0, names=list(variables.keys()) |
| 1141 | ) |
| 1142 | level_coords_dtype = {k: var.dtype for k, var in variables.items()} |
| 1143 | |
| 1144 | return cls(index, dim, level_coords_dtype=level_coords_dtype) |
| 1145 | |
| 1146 | def unstack(self) -> tuple[dict[Hashable, Index], pd.MultiIndex]: |
| 1147 | clean_index = remove_unused_levels_categories(self.index) |
nothing calls this directly
no test coverage detected