docs: def render(self,
                 *,
                 block_span_x: Optional[int] = None,
                 block_span_y: Optional[int] = None,
                 min_block_width: int = 0,
                 min_block_height: int = 0) -> str:
          """Outputs text containing the diagram.
  
          Args:
              block_span_x: The width of the diagram in blocks. Set to None to
                  default to using the smallest width that would include all
                  accessed blocks and columns with a specified minimum width.
              block_span_y: The height of the diagram in blocks. Set to None to
                  default to using the smallest height that would include all
                  accessed blocks and rows with a specified minimum height.
              min_block_width: A global minimum width for all blocks.
              min_block_height: A global minimum height for all blocks.
  
          Returns:
              The diagram as a string.
          """
  
          # Determine desired size of diagram in blocks.
          if block_span_x is None:
              block_span_x = 1 + max(
                  max(x for x, _ in self._blocks.keys()),
                  max(self._min_widths.keys()),
              )
          if block_span_y is None:
              block_span_y = 1 + max(
                  max(y for _, y in self._blocks.keys()),
                  max(self._min_heights.keys()),
              )
  
          # Method for accessing blocks without creating new entries.
          empty = Block()
          def block(x: int, y: int) -> Block:
              return self._blocks.get((x, y), empty)
  
          # Determine the width of every column and the height of every row.
          widths = {
              x: max(
                  max(block(x, y).min_width() for y in range(block_span_y)),
                  self._min_widths.get(x, 0),
                  min_block_width,
              )
              for x in range(block_span_x)
          }
          heights = {
              y: max(
                  max(block(x, y).min_height() for x in range(block_span_x)),
                  self._min_heights.get(y, 0),
                  min_block_height,
              )
              for y in range(block_span_y)
          }
  
          # Get the individually rendered blocks.
          block_renders = {
              (x, y): block(x, y).render(widths[x], heights[y])
              for x in range(block_span_x)
              for y in range(block_span_y)
          }
  
          # Paste together all of the rows of rendered block content.
          out_lines = []  # type: List[str]
          for y in range(block_span_y):
              for by in range(heights[y]):
                  out_line_chunks = []  # type: List[str]
                  for x in range(block_span_x):
                      out_line_chunks.extend(block_renders[x, y][by])
                  out_lines.append(''.join(out_line_chunks).rstrip())
  
          # Then paste together the rows.
          return '\n'.join(out_lines)