размер маркера рассеянного графика

376

В документе pyplot для точечного графика:

matplotlib.pyplot.scatter(x, y, s=20, c='b', marker='o', cmap=None, norm=None,
                          vmin=None, vmax=None, alpha=None, linewidths=None,
                          faceted=True, verts=None, hold=None, **kwargs)

Размер маркера

s: размер в пунктах ^ 2. Это скаляр или массив такой же длины, как x и y.

Что это за единица points^2? Что это значит? Имеет ли в s=100виду 10 pixel x 10 pixel?

В основном я пытаюсь составить точечные диаграммы с разными размерами маркеров, и я хочу выяснить, что означает sчисло.

LWZ
источник
почти уверен, что точки - это те же единицы, которые используются для шрифтов.
Tacaswell
@tcaswell, ты имеешь в виду, s=20значит размер маркера равен размеру fontsize=20буквы?
LWZ
нет, площадь будет 20 пунктов ^ 2, высота fontsize=20буквы 20 пунктов (или что бы ни был символ ссылки в шрифте, высота 20 пунктов).
Такасуэлл
24
matplotlib.pyplot.plot()имеет msпараметр ( markersize) эквивалентный matplotlib.pyplot.scatter()параметру s( size). Просто напоминание ..
Niekas
@neikas мне кажется, что это не так, так как один в пикселях (размер маркера), а другой в этой странной квадратной единице (размере). Меня это всегда смущало, но я считаю, что это связано с размером маркера диаграммы рассеяния, который используется для обозначения суммы визуально пропорциональным образом.
Хелтонбайкер

Ответы:

406

Это может быть несколько запутанным способом определения размера, но вы в основном указываете область маркера. Это означает, что для удвоения ширины (или высоты) маркера вам нужно увеличить sего в 4 раза. [Потому что A = W H => (2W) (2H) = 4A]

Однако существует причина, по которой размер маркеров определяется таким образом. Из-за масштабирования области как квадрата ширины удвоение ширины фактически увеличивает размер более чем в 2 раза (фактически это увеличивает его в 4 раза). Чтобы увидеть это, рассмотрим следующие два примера и вывод, который они производят.

# doubling the width of markers
x = [0,2,4,6,8,10]
y = [0]*len(x)
s = [20*4**n for n in range(len(x))]
plt.scatter(x,y,s=s)
plt.show()

дает

введите описание изображения здесь

Обратите внимание, как размер увеличивается очень быстро. Если вместо этого мы имеем

# doubling the area of markers
x = [0,2,4,6,8,10]
y = [0]*len(x)
s = [20*2**n for n in range(len(x))]
plt.scatter(x,y,s=s)
plt.show()

дает

введите описание изображения здесь

Теперь видимый размер маркеров интуитивно увеличивается примерно линейно.

Что касается точного значения того, что такое «точка», то это довольно произвольно для целей построения графика, вы можете просто масштабировать все свои размеры на константу, пока они не будут выглядеть разумно.

Надеюсь это поможет!

Изменить: (В ответ на комментарий от @Emma)

Это, вероятно, сбивает с толку формулировку с моей стороны. Был задан вопрос о удвоении ширины круга, поэтому на первом рисунке для каждого круга (когда мы двигаемся слева направо) его ширина вдвое больше предыдущей, поэтому для области это экспонента с основанием 4. Аналогично второй пример каждый круг имеет площадь, в два раза превышающую последнюю, что дает экспоненту с основанием 2.

Однако это второй пример (где мы масштабируем область), когда удваивающаяся область кажется кругу, вдвое большему глазу. Таким образом, если мы хотим, чтобы круг казался фактором nбольше, мы бы увеличили площадь nне на радиус, а на видимый размер линейно пропорционально площади.

Изменить, чтобы визуализировать комментарий @TomaszGandor:

Вот как это выглядит для разных функций размера маркера:

Экспоненциальный, квадратный или линейный размер

x = [0,2,4,6,8,10,12,14,16,18]
s_exp = [20*2**n for n in range(len(x))]
s_square = [20*n**2 for n in range(len(x))]
s_linear = [20*n for n in range(len(x))]
plt.scatter(x,[1]*len(x),s=s_exp, label='$s=2^n$', lw=1)
plt.scatter(x,[0]*len(x),s=s_square, label='$s=n^2$')
plt.scatter(x,[-1]*len(x),s=s_linear, label='$s=n$')
plt.ylim(-1.5,1.5)
plt.legend(loc='center left', bbox_to_anchor=(1.1, 0.5), labelspacing=3)
plt.show()
Дэн
источник
2
Возможно, я неправильно понимаю вашу точку зрения, но во втором примере вы увеличиваете s в геометрической прогрессии (s = [20, 40, 80, 160, 320, 640]) и говорите, что это дает нам хорошее линейное увеличение размера. Разве не имеет смысла, если линейное увеличение размера (например, s = [20, 40, 60, 80, 100, 120]) даст нам линейно выглядящий результат?
Эмма
@Emma Твоя интуиция верна, это плохая формулировка с моей стороны (или плохой выбор масштабирования по оси X). Я объяснил еще несколько в редактировании, потому что это было слишком долго для комментария.
Дан
1
Можно ли изменить sзначение в зависимости от размера окна рисунка? Я имею в виду, если мы максимизируем окна рисунков, я бы хотел иметь метки большего размера.
Сигур
2
Отличный пример (просто необходимые вещи!). Этого не должно быть 4 ** nи 2 ** n, но n ** 4и n ** 2. Со 2 ** nвторым графиком не масштабируется линейно с точки зрения диаметра круга. Это все еще идет слишком быстро (только не слишком много).
Томаш Гандор
1
Короче говоря, на втором графике показан квадратный корень из экспоненты, что является еще одной экспонентой, чуть менее крутой.
Томаш Гандор
219

Поскольку другие ответы здесь утверждают, что sобозначает область маркера, я добавляю этот ответ, чтобы прояснить, что это не обязательно так.

Размер в баллах ^ 2

Аргумент sв plt.scatterобозначает markersize**2. Как сказано в документации

s: scalar или array_like, shape (n,), необязательный
размер в точках ^ 2. По умолчанию используется rcParams ['lines.markersize'] ** 2.

Это можно воспринимать буквально. Чтобы получить маркер, который имеет x точек, вам нужно возвести это число в квадрат и дать его sаргументу.

Таким образом, отношение между размером маркера линейного графика и аргументом размера разброса является квадратом. Для того, чтобы получить маркер рассеяния того же размера, что и маркер графика размером 10 точек, вы, следовательно, позвоните scatter( .., s=100).

введите описание изображения здесь

import matplotlib.pyplot as plt

fig,ax = plt.subplots()

ax.plot([0],[0], marker="o",  markersize=10)
ax.plot([0.07,0.93],[0,0],    linewidth=10)
ax.scatter([1],[0],           s=100)

ax.plot([0],[1], marker="o",  markersize=22)
ax.plot([0.14,0.86],[1,1],    linewidth=22)
ax.scatter([1],[1],           s=22**2)

plt.show()

Подключение к «области»

Так почему же другие ответы и даже документация говорят о «области», когда дело касается sпараметра?

Конечно, единицы очков ** 2 являются единицами площади.

  • Для особого случая квадратного маркера marker="s"площадь маркера действительно является непосредственно значением sпараметра.
  • Для круга площадь круга равна area = pi/4*s.
  • Для других маркеров может даже не быть никакого очевидного отношения к области маркера.

введите описание изображения здесь

Однако во всех случаях площадь маркера пропорциональна sпараметру . Это мотивация называть это «областью», хотя в большинстве случаев это не совсем так.

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

введите описание изображения здесь

Какие очки?

Пока что ответ на вопрос, что означает размер маркера разброса, дан в единицах точек. Точки часто используются в типографии, где шрифты указаны в точках. Также ширина линий часто указывается в пунктах. Стандартный размер точек в matplotlib составляет 72 точки на дюйм (ppi) - следовательно, 1 точка составляет 1/72 дюйма.

Может быть полезно иметь возможность указывать размеры в пикселях вместо точек. Если значение dpi равно 72, одна точка - один пиксель. Если число точек на дюйм отличается (по умолчанию Matplotlib fig.dpi=100),

1 point == fig.dpi/72. pixels

Хотя размер маркера разброса в точках, следовательно, будет выглядеть по-разному для разных точек на дюйм, можно получить маркер 10 на 10 пикселей ^ 2, который всегда будет иметь одинаковое количество пикселей:

введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь

import matplotlib.pyplot as plt

for dpi in [72,100,144]:

    fig,ax = plt.subplots(figsize=(1.5,2), dpi=dpi)
    ax.set_title("fig.dpi={}".format(dpi))

    ax.set_ylim(-3,3)
    ax.set_xlim(-2,2)

    ax.scatter([0],[1], s=10**2, 
               marker="s", linewidth=0, label="100 points^2")
    ax.scatter([1],[1], s=(10*72./fig.dpi)**2, 
               marker="s", linewidth=0, label="100 pixels^2")

    ax.legend(loc=8,framealpha=1, fontsize=8)

    fig.savefig("fig{}.png".format(dpi), bbox_inches="tight")

plt.show() 

Если вас интересует разброс в единицах данных, проверьте этот ответ .

ImportanceOfBeingErnest
источник
Хотите знать, как можно рассчитать параметр s, чтобы задать разброс, чтобы получить круг, который покрывает диаметр, скажем, 0,1 в реальных координатах графика (чтобы заполнить разрыв между, скажем, 0,4 и 0,5 на графике из (0 , 0) до (1,1)?
Анатолий Алексеев
@AnatolyAlekseev Что должно ответить этот вопрос.
ImportanceOfBeingErnest
21

Вы можете использовать размер маркера, чтобы указать размер круга в методе построения

import numpy as np
import matplotlib.pyplot as plt

x1 = np.random.randn(20)
x2 = np.random.randn(20)
plt.figure(1)
# you can specify the marker size two ways directly:
plt.plot(x1, 'bo', markersize=20)  # blue circle with size 10 
plt.plot(x2, 'ro', ms=10,)  # ms is just an alias for markersize
plt.show()

От сюда

введите описание изображения здесь

Чжаоцинский
источник
Вопрос был о графике рассеяния, и в matplotlib две функции построения графиков имеют разные параметры ( размер маркера для графика и s для рассеяния ). Так что этот ответ не применяется.
Дом
3
@ Dom Я проголосовал, потому что этот вопрос всплывает как первый результат в Google, даже когда я ищу "размер маркера графика Pyplot", так что этот ответ помогает.
Przemek D
Я знаю, что метод заговора и метод разброса различаются в plt, но они оба могут реализовать «график разброса» и настроить размер маркера, так что этот ответ - еще один обходной путь, если вы используете метод заговора @Dom
zhaoqing
18

Это площадь маркера. Я имею в виду , если у вас есть s1 = 1000и то s2 = 4000, соотношение между радиусом каждого круга: r_s2 = 2 * r_s1. Смотрите следующий сюжет:

plt.scatter(2, 1, s=4000, c='r')
plt.scatter(2, 1, s=1000 ,c='b')
plt.scatter(2, 1, s=10, c='g')

введите описание изображения здесь

У меня возникли те же сомнения, когда я увидел сообщение, поэтому я сделал этот пример, затем использовал линейку на экране для измерения радиусов.

Joaquin
источник
Это самый чистый и самый обезжиренный ответ. Спасибо
Аян Митра
6

Я также попытался сначала использовать «разброс» для этой цели. После довольно много потерянного времени - я остановился на следующем решении.

import matplotlib.pyplot as plt
input_list = [{'x':100,'y':200,'radius':50, 'color':(0.1,0.2,0.3)}]    
output_list = []   
for point in input_list:
    output_list.append(plt.Circle((point['x'], point['y']), point['radius'], color=point['color'], fill=False))
ax = plt.gca(aspect='equal')
ax.cla()
ax.set_xlim((0, 1000))
ax.set_ylim((0, 1000))
for circle in output_list:    
   ax.add_artist(circle)

введите описание изображения здесь

Это основано на ответе на этот вопрос

Айк
источник
очень полезно. Но зачем использовать две петли?
grabantot
1
@grabantot без причины, просто не слишком задумывался об этом.
Ike
2

Если размер кружков соответствует квадрату параметра в s=parameter, то присвойте квадратный корень каждому элементу, который вы добавляете в массив размеров, например, так s=[1, 1.414, 1.73, 2.0, 2.24], что когда он принимает эти значения и возвращает их, их относительное увеличение размера будет квадратный корень квадратной прогрессии, который возвращает линейную прогрессию.

Если бы я был на площадь каждого из них , как он получает выход к сюжету: output=[1, 2, 3, 4, 5]. Попробуйте интерпретацию списка:s=[numpy.sqrt(i) for i in s]

user34028
источник
1
Должно быть i in outputне должно?
Сигур