Круг Боке не вписывается в квадрат?

#python #bokeh

#python #геометрия #боке

Вопрос:

Я строю некоторую геометрию, используя боке, и наткнулся на это. Я строю прямоугольник с равными сторонами (т.Е. Квадрат), и в этом квадрате строю круг с диаметром = шириной квадрата. Окружность должна касаться квадрата по краям, но это не так.

вот код:

 from bokeh.plotting import output_notebook, figure, show
output_notebook()

p = figure(width=500, height=500)

p.rect(0, 0, 300, 300, line_color='black')
p.circle(x=0, y=0, radius=150, line_color='black', 
         fill_color='grey',  radius_units='data')

p.axis.minor_tick_out = 0

show(p)
 

Что приводит к этому:

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

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

Заранее спасибо, Рэндалл

Вот еще один случай — просто рисуем круг:

 p = figure(width=500, height=500, x_range=(-150, 150), y_range=(-150, 150))
p.circle(x=0, y=0, radius=150, line_color='black', 
         fill_color='grey', radius_units='data')
show(p)
 

радиус окружности равен 150 в направлении x, но не в направлении y.

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

Комментарии:

1. Если круг в bokeh не является кругом, возможно, вам следует проверить, зарегистрирована ли эта проблема на их страницах github, и если нет, сообщите об этом

2. Хороший момент. Я разместил его на гитхабе bokeh. Надеялся, что есть что-то простое, что я делаю неправильно. Ссылка на выпуск: github.com/bokeh/bokeh/issues/6603

3. @RandallGoodwin привет, я опубликовал ответ ниже, для меня это имеет смысл и не кажется проблемой. Я предполагаю, что это зависит от того, что вы ожидаете p.circle сделать, я ожидаю, что это создаст точечные диаграммы, поэтому описанное выше поведение кажется мне разумным.

4. Пожалуйста, обратите внимание на новый ответ @DuCorey ниже относительно сопоставления аспектов в боке 0.12.7

Ответ №1:

Я хотел бы сообщить, что начиная с версии Bokeh 0.12.7, эта проблема теперь может быть устранена более простым способом.

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

Начиная с версии 0.12.7, рисунки теперь могут принимать match_aspect свойство, которое при установке значения True будет сопоставлять аспект пространства данных с пространством пикселей графика.

В вашем примере просто добавьте match_aspect = True в свой рисунок

 p = figure(width=500, height=500, match_aspect=True, 
           title="Circle touches all 4 sides of square")
p.rect(0, 0, 300, 300, line_color='black')
p.circle(x=0, y=0, radius=150, line_color='black', 
         fill_color='grey',  radius_units='data')
 

теперь будет выдавать

Круг касается всех 4 сторон квадрата

Ответ №2:

ОБНОВЛЕНИЕ: пожалуйста, обратите внимание на новый ответ @DuCorey ниже. Начиная с версии Bokeh 0.12.7, для подобных ситуаций теперь доступно управление аспектами.


Проблема на самом деле в том, что квадрат не является квадратным, и это потому, что соотношение сторон в пикселях и соотношение сторон «данных» не совпадают. т. Е. Расстояние на пиксель отличается в направлении x, чем в направлении y.

Есть несколько вариантов:

  • Вы можете использовать различные свойства для управления размерами центральной области графика (например, шириной границы графика и ориентацией метки оси) Вы также можете явно управлять диапазонами данных. Другими словами, вы можете сделать так, чтобы соотношения сторон совпадали, и тогда окружность и прямоугольник будут совпадать
  • Вы можете использовать абсолютные единицы измерения в пикселях (например size , для круга и использовать большой square маркер вместо rect ) вместо единиц измерения «данных».

В качестве альтернативы, если вам нужен круг, который «деформируется», когда аспекты не совпадают, тогда лучше всего использовать ellipse с идентичным width и height , который будет работать, потому что в этом случае боке имеет два измерения для измерения (вместо одного radius ) и может сопоставлять каждое с масштабом вдолькаждое измерение независимо.

(На самом деле это фундаментальное различие, объясняющее поведение: rect имеет два измерения для независимого измерения. circle нет, он имеет только один и должен произвольно использовать измерение x или y для измерения расстояния на пиксель)

Комментарии:

1. спасибо @bigreddot. Попробую некоторые из этих вариантов и отчитаюсь 🙂

Ответ №3:

хорошо, основываясь на предложениях, я попробовал несколько вещей.

  • Изменена ориентация меток по оси y — все еще была проблема.
  • Изменены различные препятствия, даже перемещение меток внутри графика (с отрицательным смещением). Тоже не сработало.
  • Изменил значения x_range и r_range в figure() на равные кортежи. Тоже не сработало
  • Изменяет plot_height (уменьшает его), и я мог бы в конечном итоге, с помощью ошибок и ошибок, заставить круг вписаться в квадрат с plot_height, который был < ширина участка.

Много отличной практики, управляющей атрибутами графика. Время будет потрачено.

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

Как ни странно, настройка p.min_border=40 , которая на 0.12.6 является значением по умолчанию, и вуаля, на экране также отображается соотношение сторон диаграммы для диаграммы, где plot_width=plot_height действительно равно 1.

 p = figure(plot_width=500, plot_height=500)

p.rect(0, 0, 300, 300, line_color=None)

p.circle(x=0, y=0, radius=150, line_color=None, 
         fill_color='lightgrey',  radius_units='data')

p.min_border=40

show(p)
 

Изображения до и после, показывающие эффект добавления p.min_border=40 . Любого значения, превышающего ~ 33, оказалось достаточно, чтобы область графика имела одинаковый размер экрана x и y — так что квадрат действительно был квадратом (и круг помещался внутри).

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

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

Комментарии:

1. Это также исправляет соотношение сторон кольца. Спасибо!!!!!!!!!

Ответ №4:

Не уверен, но прямоугольник bleu — это не ваш прямоугольник.

Заменить:

 p.rect(0, 0, 300, 300, line_color='black')
 

Автор::

 p.rect(-150, -150, 150, 150, line_color='black')
 

Комментарии:

1. Это просто перемещает квадрат так, чтобы он был центрирован на -150, -150. Я добавил еще один тест — просто нарисовать круг радиусом = 150. На этот раз нет прямоугольника (или квадрата). В направлении x r = 150, но не в направлении y.

Ответ №5:

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

Я думаю rect , что здесь «случается» работать, потому что он может правильно масштабироваться в обоих измерениях и оставаться «прямоугольником».

 Keyword Args:
    radius (UnitsSpecPropertyDescriptor) : The radius values for circle markers (in "data space" units, by default). (default None)
    radius_dimension (BasicPropertyDescriptor) : What dimension to measure circle radii along. (default 'x')
    radius_units (Enum('screen', 'data')) :  (default 'data')
 

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

Если вы хотите создать фактический круг, вы можете сделать следующее:

 th = np.linspace(0, 2*np.pi)

r = 150

p = figure(width=500, height=500)

p.rect(0, 0, 300, 300, line_color='black')

p.line(r * np.cos(th), r * np.sin(th), line_color='black')
# p.circle(x=0, y=0, radius=150, line_color='black',
#         fill_color='grey', radius_units='data')

p.axis.minor_tick_out = 0

show(p)
 

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