code: def prepare_weighted_spans(targets,  # type: List[TargetExplanation]
                             preserve_density=None,  # type: Optional[bool]
                             ):
      # type: (...) -> List[Optional[List[PreparedWeightedSpans]]]
      
      targets_char_weights = [
          [get_char_weights(ws, preserve_density=preserve_density)
           for ws in t.weighted_spans.docs_weighted_spans]
           if t.weighted_spans else None
           for t in targets]  # type: List[Optional[List[np.ndarray]]]
      max_idx = max_or_0(len(ch_w or []) for ch_w in targets_char_weights)
  
      targets_char_weights_not_None = [
          cw for cw in targets_char_weights
          if cw is not None]  # type: List[List[np.ndarray]]
  
      spans_weight_ranges = [
          max_or_0(
              abs(x) for char_weights in targets_char_weights_not_None
              for x in char_weights[idx])
          for idx in range(max_idx)]
      return [
          [PreparedWeightedSpans(ws, char_weights, weight_range)
           for ws, char_weights, weight_range in zip(
              t.weighted_spans.docs_weighted_spans,  # type: ignore
              t_char_weights,
              spans_weight_ranges)]
          if t_char_weights is not None else None
          for t, t_char_weights in zip(targets, targets_char_weights)]
docs: Return weighted spans prepared for rendering.
      Calculate a separate weight range for each different weighted
      span (for each different index): each target has the same number
      of weighted spans.