code: def choose_ancestral_states_joint(tree, feature, states, frequencies):
      
      lh_feature = get_personalized_feature_name(feature, BU_LH)
      lh_state_feature = get_personalized_feature_name(feature, BU_LH_JOINT_STATES)
      allowed_state_feature = get_personalized_feature_name(feature, ALLOWED_STATES)
      joint_state_feature = get_personalized_feature_name(feature, JOINT_STATE)
      _, state2array = get_state2allowed_states(states, False)
  
      def chose_consistent_state(node, state_index):
          node.add_feature(joint_state_feature, state_index)
          node.add_feature(allowed_state_feature, state2array[state_index])
  
          for child in node.children:
              chose_consistent_state(child, getattr(child, lh_state_feature)[state_index])
  
      chose_consistent_state(tree, (getattr(tree, lh_feature) * frequencies).argmax())
docs: Chooses node ancestral states based on their marginal probabilities using joint method.
  
      :param frequencies: numpy array of state frequencies
      :param tree: ete3.Tree, the tree of interest
      :param feature: str, character for which the ancestral states are to be chosen
      :param states: numpy.array of possible character states in order corresponding to the probabilities array
      :return: void, modified the get_personalized_feature_name(feature, ALLOWED_STATES) feature of each node
          to only contain the selected states.