#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')
теперь будет выдавать
Ответ №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)
Обратите внимание, что вышеизложенное сложнее заполнить (я не беспокоился), потому что я предполагаю, что вам нужно определить некоторую функцию замкнутого полигона, в то время как я определил только линию, которая является замкнутым полигоном, в данном случае кругом.