Сейчас я напишу тебе программу на языке python, на входе которой словарь с данными, а на выходе рисуется картинка, содержащая таблицу.

def draw_run_information(image, draw, font_session_numbers, font_session_names, run, column_widths, column_spacing, row_height, start_coordinate_x, start_coordinate_y):
    TINT_COLOR = (0, 0, 0)  # Black
    TRANSPARENCY = 0.3  # Degree of transparency, 0-100%
    OPACITY = int(255 * TRANSPARENCY)
    overlay = Image.new('RGBA', image.size, TINT_COLOR+(0,))

    draw_overlay = ImageDraw.Draw(overlay)  # Create a context for drawing things on it.

    original_image = image

    for col in range(5):
        cell_width = column_widths[col]

        # Рисуем ячейку
        draw_overlay.rectangle([(start_coordinate_x, start_coordinate_y), (start_coordinate_x + cell_width, start_coordinate_y + row_height)], outline=(255, 165, 0, 72), fill=TINT_COLOR+(OPACITY,))
        
        if col == 0:  # Для первого столбца
            add_weather_icon(overlay, run["run_weathercode"], cell_width, row_height, start_coordinate_x, start_coordinate_y)
        
        elif col == 1:
            draw_text(draw_overlay, font_session_names, run["run_name"], cell_width, row_height, start_coordinate_x, start_coordinate_y)
        
        elif col == 2:
            add_thermometer_icon(overlay, draw_overlay, font_session_numbers, run["run_temperature"], cell_width, row_height, start_coordinate_x, start_coordinate_y)

        elif col == 3:
            add_drops_icon(overlay, draw_overlay, font_session_numbers, run["run_rain_probability"], cell_width, row_height, start_coordinate_x, start_coordinate_y)
          
        elif col == 4:
            add_clock_icon(overlay, draw_overlay, font_session_numbers, run["run_time"], cell_width, row_height, start_coordinate_x, start_coordinate_y)

        start_coordinate_x += cell_width + column_spacing  # переходим к следующей ячейке
      
    # Alpha composite these two images together to obtain the desired result.
    original_image = Image.alpha_composite(original_image, overlay)  
    image = original_image
    return image


def draw_table_with_dates(runs):
    # Открываем изображение фона
    background = Image.open("background.png")
    image_width, image_height = background.size
  
    # Создаем изображение размером 1080x1350 пикселей
    image = Image.new("RGBA", (1080, 1350), (255, 255, 255))
    image.paste(background, (0, 0))
    draw = ImageDraw.Draw(image)

    # Задаем параметры таблицы
    row_height = 75
    column_widths = [75, 305, 125, 125, 150]
    column_spacing = 10
    row_spacing = 10

    run_data_font = ImageFont.truetype("fonts/RunDataFont.ttf", size=28)
    run_session_names_data_font = ImageFont.truetype("fonts/RunDataFont.ttf", size=35)
    date_header_font = ImageFont.truetype("fonts/DateHeaderFont.ttf", size=45)
    gp_name_font = ImageFont.truetype("fonts/GrandPrixNameFont.ttf", size=80)
    
    image = add_track_image(image)
    #image = add_text_and_flag(image)
    add_GP_name_and_flag(image, draw, gp_name_font, "ГРАН-ПРИ ЭМИЛИИ-РОМАНЬИ", column_widths, column_spacing, row_height)
    
    # Вычисляем положение таблицы
    table_width = sum(column_widths) + column_spacing * (len(column_widths) - 1)
    table_height = row_height * 5

    x = 135
    y = 150 #500

    current_table_row = 0
    current_run = 0
    active_run_flag = 0
    # Рисуем таблицу
    for row in range(8):
        if current_table_row == 0:
            image = draw_date_header_new(image, runs[current_run]["run_date"], date_header_font, row_height, x, y)

        elif current_table_row == 1:
            image = draw_run_information(image, draw, run_data_font, run_session_names_data_font, runs[current_run], column_widths, column_spacing, row_height, x, y)
            current_run += 1
      
        elif current_table_row >= 2:
            if runs[current_run]["run_date"] != runs[current_run - 1]["run_date"] and active_run_flag == 0:
                image = draw_date_header_new(image, runs[current_run]['run_date'], date_header_font, row_height, x, y)
                active_run_flag = 1

            else:
                image = draw_run_information(image, draw, run_data_font, run_session_names_data_font, runs[current_run], column_widths, column_spacing, row_height, x, y)
                current_run += 1
                active_run_flag = 0

        # Переходим на новую строку
        x = (image.width - table_width) // 2
        y += row_height + row_spacing
        current_table_row += 1

    # Сохраняем изображение в файл
    image.save("table_with_dates.png")

Сделай так, чтобы над 3, 4 и 5 ячейками второй строки появились надписи "Температура", "Вероятность дождя" и "Московское время" соответственно. Каждая из надписей должна быть выровнена по ширине относительно соответствующей ячейки.