@@ -741,29 +741,22 @@ def set_levels(
741741 ValueError
742742 If the length of the values is not equal to the length of the index
743743 """
744- # set the levels specified in levels_to_set to the provided values
745- #
746- # We should support both single values e.g. levels_to_set={"variable": "Emissions"}
747- # and values with the same length as the index itself e.g.
748- # levels_to_set={"variable": ["a", "b", "c"]}.
749- # Values of any other length should raise an error (because we don't know what to do
750- # if the index is say 4 elements long but the user only gives us 3 values)
751- #
752- # This should work whether the level to be set exists or not
753- # TODO: move to pandas-openscm
754- # TODO: split out method that just works on MultiIndex
755-
756- new_names = levels_to_set .keys ()
757- new_values = levels_to_set .values ()
758-
759744 if not isinstance (ini , pd .MultiIndex ):
760- raise TypeError (ini )
745+ msg = f"Expected MultiIndex, got { type (ini )} "
746+ raise TypeError (msg )
761747
762- return pd .MultiIndex (
763- codes = [
764- * ini .codes , # type: ignore # not sure why check above isn't working
765- * ([[0 ] * ini .shape [0 ]] * len (new_values )), # type: ignore # fix when moving to pandas-openscm
766- ],
767- levels = [* ini .levels , * [pd .Index ([value ]) for value in new_values ]], # type: ignore # fix when moving to pandas-openscm
768- names = [* ini .names , * new_names ], # type: ignore # fix when moving to pandas-openscm
769- )
748+ df = ini .to_frame (index = False )
749+
750+ for level , value in levels_to_set .items ():
751+ if isinstance (value , Collection ) and not isinstance (value , str ):
752+ if len (value ) != len (ini ):
753+ msg = (
754+ f"Length of values for level '{ level } ' does not "
755+ f"match index length: { len (value )} != { len (ini )} "
756+ )
757+ raise ValueError (msg )
758+ df [level ] = value
759+ else :
760+ df [level ] = [value ] * len (ini )
761+
762+ return pd .MultiIndex .from_frame (df )
0 commit comments