Положение участка/разброса и размер маркера в тех же координатах

Я пытаюсь программно отображать различные типы диаграмм в pylab. Функция разброса pylab отображает маркеры в разных координатах по темпам своей оси, но размеры маркеров соответствуют пикселям. Это имеет смысл для ежедневных графиков. Однако я хочу дать координаты и размеры маркера в тех же координатах! например, следующий код отображает два круга в (0,0,0,0) и (0,5,0,5) с размерами по 20 каждый. Они должны перекрываться почти полностью, так как радиус намного больше расстояния между центрами. Однако они не связаны с тем, что размеры находятся в пикселях, а позиции - в координатах оси.

import pylab
pylab.scatter([0,0.5], [0,0.5], s=20, c='b', marker='o')

Есть ли способ сделать диаграмму рассеяния (или рисовать любые фигуры, линии и т.д.) с размерами и позициями, заданными в тех же координатах? Меня интересует вывод векторной графики (pdf, svg и т.д.).

Ответ 1

Функция pylab.scatter принимает размер значения, основанный на размере в точках ^ 2. Этот размер не зависит от осей, так же как и характер диаграммы рассеяния (не имеет смысла, если вы уклоняетесь от области на участке рассеяния, что точки становятся больше).

Если вы хотите сказать, чтобы рисовать круги заданного размера, вы должны использовать команду circle в pylab

import pylab
axes = pylab.axes()
circle1 = pylab.Circle((0,0), radius=20, alpha=.5)
circle2 = pylab.Circle((0.5,0.5), radius=20, alpha=.5)
axes.add_patch(circle1)
axes.add_patch(circle2)
pylab.axis('scaled')
pylab.show()

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

import pylab
import matplotlib

def my_circle_scatter(axes, x_array, y_array, radius=0.5, **kwargs):
    for x, y in zip(x_array, y_array):
        circle = pylab.Circle((x,y), radius=radius, **kwargs)
        axes.add_patch(circle)
    return True

def my_square_scatter(axes, x_array, y_array, size=0.5, **kwargs):
    size = float(size)
    for x, y in zip(x_array, y_array):
        square = pylab.Rectangle((x-size/2,y-size/2), size, size, **kwargs)
        axes.add_patch(square)
    return True

def my_polygon_scatter(axes, x_array, y_array, resolution=5, radius=0.5, **kwargs):
    ''' resolution is number of sides of polygon '''
    for x, y in zip(x_array, y_array):
        polygon = matplotlib.patches.CirclePolygon((x,y), radius=radius, resolution=resolution, **kwargs)
        axes.add_patch(polygon)
    return True

axes=pylab.axes()
my_circle_scatter(axes, [0,0.5], [0,0.5], radius=2, alpha=.5, color='b')
my_square_scatter(axes, [-3,-4,2,3], [1,-3,0,3], size=.5, alpha=.5, color='r')
my_polygon_scatter(axes, [-1,-2,3], [-3,0,3], radius=.5, resolution=3, alpha=.5, color='g')
my_polygon_scatter(axes, [4,1.5,3], [2,-1,-3], radius=.5, resolution=5, alpha=.5, color='k')
pylab.axis('scaled')
pylab.axis([-5,5,-5,5])
pylab.show()

См. http://matplotlib.sourceforge.net/api/artist_api.html#module-matplotlib.patches для других доступных объектов.

Пример вывода из первого фрагмента: matplotlib circles

Пример вывода из второго фрагмента: matplotlib scatter plot

EDIT для Griff: если вы хотите обрабатывать другой радиус для каждой точки, вы можете сделать что-то прямое:

def my_circle_scatter_radii(axes, x_array, y_array, radii_array, **kwargs):
    for (x, y, r) in zip(x_array, y_array, radii_array):
        circle = pylab.Circle((x,y), radius=r, **kwargs)
        axes.add_patch(circle)
    return True

Логика для обработки обоих случаев одновременно также проста (например, проверьте, является ли ее radii_array int/float, и если это делает его массивом).

Ответ 2

Коллекция патчей - лучший выбор, если вы действительно хотите сделать его похожим на plt.scatter. Предположим, вы хотите построить разброс кругов с заданным радиусом в блоке данных, вы можете взглянуть на этот пост, который обеспечивает хорошо обернутую функцию с именем circles.

Если вы хотите использовать другие маркеры, такие как квадрат или многоугольник, вы можете переписать эту функцию с соответствующими исправлениями, как сказано в ответе dr jimbob.

Здесь пример

from pylab import *
figure(figsize=(6,4))
ax = subplot(aspect='equal')

#plot a set of circle
a = arange(11)
circles(a, a, s=a*0.2, c=a, alpha=0.5, ec='none')
colorbar() 

#plot a circle (the lower-right one)
circles(1, 0, s=0.4, c='r', ls='--', lw=5, fc='none', transform=ax.transAxes)

xlim(0,10)
ylim(0,10)

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