Размещение точек с переменной плотностью

Предположим, что у вас есть матрица NxM со значениями в диапазоне от [0,100]. Я бы хотел разместить точки с плотностью (обратно) относительно значений в этой области.

Например, вот двумерное гауссово поле, инвертированное s.t. центроид имеет значение 0, а периметр равен 100:

Размещение точек с переменной плотностью

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

Размещение точек с переменной плотностью

Обратите внимание на радиальное распространение наружу.

Моя попытка выглядит немного иначе :( ...

Размещение точек с переменной плотностью

Я пытаюсь (i) создать логическую область той же формы и размера и (ii) перемещаться по строкам и столбцам. Если значение логического массива в какой-то момент равно True, то передать; в противном случае добавьте точку [row,col] в список и закройте логический массив True в радиусе, пропорциональном значению в гауссовском массиве.

Выбор гауссиана для этого примера не важен, основная идея заключается в следующем: учитывая матрицу с плавающей запятой, как можно разместить точки с плотностью, пропорциональной этим значениям?

Любая помощь очень ценится :)

import matplotlib.pyplot as plt
import numpy as np
from math import exp

def gaussian(x,y,x0,y0,A=10.0,sigma_x=10.0,sigma_y=10.0):
    return A - A*exp(-((x-x0)**2/(2*sigma_x**2) + (y-y0)**2/(2*sigma_y**2)))

def generate_grid(width=100,height=100):
    grid = np.empty((width,height))
    for x in range(0,width):
        for y in range(0,height):
            grid[x][y] = gaussian(x,y,width/2,height/2,A=100.0)
    return grid

def cover_array(a,row,col,radius):
    nRows = np.shape(grid)[0]
    nCols = np.shape(grid)[1]
    mid = round(radius / 2)
    half_radius = int(round(radius))
    for x in range(-half_radius,half_radius):
        for y in range(-half_radius,half_radius):
            if row+x >= 0 and x+row < nRows and col+y >= 0 and y+col < nCols:
                if (x-mid)**2 + (y-mid)**2 <= radius**2:
                    a[row+x][col+y] = True


def pack_points(grid):
    points = []
    nRows = np.shape(grid)[0]
    nCols = np.shape(grid)[1]
    maxDist = 50.0
    minDist = 0.0
    maxEdge = 10.0
    minEdge = 5.0
    grid_min = 0.0
    grid_max = 100.0

    row = 0
    col = 0

    arrayCovered = np.zeros((nRows,nCols))

    while True:
        if row >= nRows:
            return np.array(points)

        if arrayCovered[row][col] == False:
            radius = maxEdge * ((grid[row][col] - grid_min) / (grid_max - grid_min))
            cover_array(arrayCovered,row,col,radius)
            points.append([row,col])

        col += 1
        if col >= nCols:
            row += 1
            col = 0

grid = generate_grid()
plt.imshow(grid)
plt.show()

points = pack_points(grid)

plt.scatter(points[:,0],points[:,1])
plt.show()

Нужно ли каким-то образом «выровнять» точки, или это нормально, если они будут размещены произвольно, но с адекватной плотностью?

jdehesa 14.03.2018 17:30

@jdehesa Просто плотность важна. Спасибо!

Daniel R. Livingston 14.03.2018 17:32

Сначала сложите плотности всех точек в любом порядке, вычисляя для i-й точки соответствующий интервал (sumOfDensitiesUpToPoint [i-1], sumOfDensitiesUpToPoint [i]). Теперь выберите случайное число от 0 до общей суммы и выясните, в какой интервал оно попадает - это подскажет вам местоположение этого образца. При необходимости повторите. (Вы можете записать точки, которые уже были отобраны, и повторить их). Вы можете ускорить поиск интервала с помощью двоичного поиска.

j_random_hacker 14.03.2018 18:04
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
3
86
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вот дешевый и простой метод, хотя он требует ручной настройки параметра amount:

import numpy as np
import matplotlib.pyplot as plt

def gaussian(x,y,x0,y0,A=10.0,sigma_x=10.0,sigma_y=10.0):
    return A - A*np.exp(-((x-x0)**2/(2*sigma_x**2) + (y-y0)**2/(2*sigma_y**2)))

def distribute_points(data, amount=1):
    p = amount * (1 / data)
    r = np.random.random(p.shape)
    return np.where(p > r)

ii, jj = np.mgrid[-10:10:.1, -10:10:.1]
data = gaussian(ii, jj, 0, 0)
px, py = distribute_points(data, amount=.03)

plt.imshow(data)
plt.scatter(px, py, marker='.', c='#ff000080')
plt.xticks([])
plt.yticks([])
plt.xlim([0, len(ii)])
plt.ylim([0, len(jj)])

Результат:

Points

Другие вопросы по теме