Усы Matplotlib boxplot той же ширины, что и коробка - PullRequest
0 голосов
/ 03 апреля 2020

Я хотел бы создать боксплот в matplotlib, где х-экстент колпачков усов такой же, как х-экстент бокса.

Здесь я генерирую несколько простых боксплотов:

import matplotlib.pyplot as plt
import numpy as np

data = np.random.normal(size=(100, 3))

fig, ax = plt.subplots(1, 1)
ax.boxplot(data)

enter image description here

Обратите внимание на то, что коробки на бокс-плодах шире, чем крышки для усов. Я хотел бы, чтобы эти элементы были одинаковой ширины.

1 Ответ

2 голосов
/ 03 апреля 2020

На аналогичный вопрос отвечает здесь . Тем не менее, связанный вопрос спрашивает о графике, созданном с seaborn, а не непосредственно с matplotlib. Решение здесь аналогично, но требует некоторых незначительных корректировок:

import matplotlib.pyplot as plt
import numpy as np

data = np.random.normal(size=(100, 3))

fig, ax = plt.subplots(1, 1)
ax.boxplot(data)

# Loop over the 3 boxes
for i in range(3):
    # Set the limits of the lower whisker to be the same as the box limits
    ax.lines[i*7 + 3].set_xdata(ax.lines[i*7 + 5].get_xdata())
    # Set the limits of the upper whisker to be the same as the box limits
    ax.lines[i*7 + 4].set_xdata(ax.lines[i*7 + 5].get_xdata())

enter image description here

Обратите внимание, что если вы передаете аргумент showfliers=False вызову plt.boxplot результирующие оси будут содержать только 6 строк, а не 7. Наш код должен затем стать:

for i in range(3):
    ax.lines[i*6 + 3].set_xdata(ax.lines[i*6 + 5].get_xdata())
    ax.lines[i*6 + 4].set_xdata(ax.lines[i*6 + 5].get_xdata())

Передача других аргументов в вызов plt.boxplot может дополнительно изменить количество экземпляров строки нашего оси. Необходимость изменять наш код при изменении аргументов, переданных в plt.boxplot, - боль

Лучшим решением было бы сохранить данные, возвращаемые вызовом на plt.boxplot, и использовать это напрямую:

fig, ax = plt.subplots(1, 1)
# Keep hold of the returned
box = ax.boxplot(data)

# Loop over the 3 boxes
for i in range(3):
    # Adjust the lower cap
    box['caps'][2*i].set_xdata(box['boxes'][i].get_xdata()[:2])
    # Adjust the upper cap
    box['caps'][2*i + 1].set_xdata(box['boxes'][i].get_xdata()[:2])

Это лучше, хотя мы все еще жестко программируем 3 бокса (range(3)). Мы можем избавиться от этого как:

fig, ax = plt.subplots(1, 1)
# Keep hold of the returned
box = ax.boxplot(data)

# Loop over the n boxes
for i, box_lines in enumerate(box['boxes']):
    # Adjust the lower cap
    box['caps'][2*i].set_xdata(box_lines.get_xdata()[:2])
    # Adjust the upper cap
    box['caps'][2*i + 1].set_xdata(box_lines.get_xdata()[:2])

Кроме того, тот же результат может быть достигнут для горизонтальных боксов, если мы вместо этого изменим ydata:

fig, ax = plt.subplots(1, 1)
box = ax.boxplot(data, vert=False)

# Loop over the n boxes
for i, box_lines in enumerate(box['boxes']):
    # Adjust the lower cap
    box['caps'][2*i].set_ydata(box_lines.get_ydata()[:2])
    # Adjust the upper cap
    box['caps'][2*i + 1].set_ydata(box_lines.get_ydata()[:2])

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...