График изображения в боке с жесткими осями и соответствующим соотношением сторон - PullRequest
0 голосов
/ 04 декабря 2018

Я использую версию bokeh 1.0.1 внутри приложения Django, и я хотел бы отображать микроскопические изображения поверхности в виде масштабируемых графиков с цветовой кодировкой высоты и цветовой шкалы.В принципе это работает, но у меня проблемы с получением графиков с правильным соотношением сторон, показывающих только изображение без пробелов.

Вот пример того, чего я хочу достичь: Получившийся график должен

  • показывает изображение случайных данных, имеющих ширину sx=10 и высоту sy=5 в пространстве данных (изображение размер )
  • с осями, ограниченными (0,sx) и (0,sy), при начальном виде и при увеличении
  • квадрат на экране должен совпадать с квадратом в пространстве данных, по крайней мере, при начальном виде

Для изображения, которое я простоиспользуйте случайные данные с nx=100 точками в направлении x и ny=100 точками в направлении y.

Вот мой первый подход:

Попытка 1

from bokeh.models.ranges import Range1d
from bokeh.plotting import figure, show
from bokeh.models import LinearColorMapper, ColorBar
import numpy as np

sx = 10
sy = 5

nx = 100
ny = 100    
arr = np.random.rand(nx, ny)

x_range = Range1d(start=0, end=sx, bounds=(0,sx))
y_range = Range1d(start=0, end=sy, bounds=(0,sy))

# Attempt 1
plot = figure(x_range=x_range, y_range=y_range, match_aspect=True)

# Attempt 2
# plot = figure(match_aspect=True)

# Attempt 3
# pw = 400
# ph = int(400/sx*sy)
# plot = figure(plot_width=pw, plot_height=ph, 
#               x_range=x_range, y_range=y_range, match_aspect=True)

color_mapper = LinearColorMapper(palette="Viridis256", 
                                 low=arr.min(), high=arr.max())
colorbar = ColorBar(color_mapper=color_mapper, location=(0,0))

plot.image([arr], x=[0], y=[0], dw=[sx], dh=[sy],  
           color_mapper=color_mapper)
plot.rect(x=[0,sx,sx,0,sx/2], y=[0,0,sy,sy,sy/2], 
          height=1, width=1, color='blue')

plot.add_layout(colorbar, 'right')    
show(plot)

IМы также добавили синие квадраты к графику, чтобы увидеть, когда требование соотношения сторон не выполняется.

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

Попытка 2

При выходе из диапазонов с помощью

plot = figure(match_aspect=True)

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

Попытка 3

В качестве альтернативы, при предоставлении фигуре plot_height и plot_width с предопределенным аспектомнапример, соотношение

pw = 800 # plot width
ph = int(pw/sx*sy)
plot = figure(plot_width=pw, plot_height=ph, 
              x_range=x_range, y_range=y_range, 
              match_aspect=True)

Я получу это изображение .Квадрат тоже не квадрат.Это можно сделать почти, но это сложно, потому что plot_width также включает в себя цветную полосу и панель инструментов.

Я прочитал это соответствующее сообщение в блоге и соответствующую документацию по боке , но я не могу заставить его работать.

Кто-нибудь знает, как добиться того, чего я хочу, или это невозможно?Адаптивное поведение также было бы неплохо, но мы можем пока пренебречь этим.Спасибо за любую подсказку.

Обновление

После разговора с разработчиком Bokeh о Gitter (спасибо Брайану!) Кажется, что то, что я хочу, практически невозможно.

Причина в том, как match_aspect=True работает, чтобы квадрат в пространстве данных выглядел как квадрат в пиксельном пространстве: учитывая размер холста, который может возникнуть в результате применения различных настроек sizing_mode для адаптивного поведениязатем диапазон данных изменяется, чтобы иметь соответствующее соотношение сторон.Таким образом, нет другого способа сделать соотношение сторон пикселя таким, чтобы оно соответствовало соотношению сторон данных, без добавления дополнительного пространства вокруг изображения, то есть для расширения осей по заданным границам.Также см. Комментарий к этой проблеме .

Можно выполнить без адаптивного поведения и затем предварительно зафиксировать размер холста с учетом соотношения сторон, но в настоящее время не совсем идеально из-за всех остальныхэлементы вокруг внутренней рамки, которые также занимают место.Существует PR , который может позволить прямой контроль размеров внутренней рамы, но я не уверен, как это сделать.

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

Я пытался использовать различные атрибуты range_padding*, например

x_range = DataRange1d(range_padding=10, range_padding_units='percent')
y_range = DataRange1d(range_padding=10, range_padding_units='percent')

но это не уменьшает объем пространства вокруг графика, а только увеличивает его.Заполнение в процентах должно быть относительно размеров изображения, заданных dh и dw.

Кто-нибудь знает, как использовать параметры range_padding, чтобы иметь меньшие диапазоны осей, или другой способ иметь меньшие отступы вокруг графика изображения в примере выше (используя match_aspect=True)?Я открыл другой вопрос по этому вопросу.

1 Ответ

0 голосов
/ 19 марта 2019

Можете ли вы принять это решение (работает с Bokeh v1.0.4)?

from bokeh.models.ranges import Range1d
from bokeh.plotting import figure, show
from bokeh.layouts import Row
from bokeh.models import LinearColorMapper, ColorBar
import numpy as np

sx = 10
sy = 5

nx = 100
ny = 100
arr = np.random.rand(nx, ny)

x_range = Range1d(start = 0, end = sx, bounds = (0, sx))
y_range = Range1d(start = 0, end = sy, bounds = (0, sy))

pw = 400
ph = pw * sy / sx
plot = figure(plot_width = pw, plot_height = ph,
              x_range = x_range, y_range = y_range, match_aspect = True)

color_mapper = LinearColorMapper(palette = "Viridis256",
                                 low = arr.min(), high = arr.max())

plot.image([arr], x = [0], y = [0], dw = [sx], dh = [sy], color_mapper = color_mapper)
plot.rect(x = [0, sx, sx, 0, sx / 2], y = [0, 0, sy, sy, sy / 2], height = 1, width = 1, color = 'blue')

colorbar_plot = figure(plot_height = ph, plot_width = 69, x_axis_location = None, y_axis_location = None, title = None, tools = '', toolbar_location = None)
colorbar = ColorBar(color_mapper = color_mapper, location = (0, 0))
colorbar_plot.add_layout(colorbar, 'left')

show(Row(plot, colorbar_plot))

Результат:

enter image description here

...