Переключение источника данных для графика hbar в режиме боке не работает: пустой график

#python #pandas #bokeh

#python #pandas #bokeh

Вопрос:

Проблема

Я хотел создать интерактивный график hbar, где вы можете переключаться между 3 различными источниками данных, используя виджет выбора, обратный вызов python и локальную подачу bokeh. График с источником по умолчанию отображается нормально, но когда я переключаюсь на другой источник, метки y остаются прежними, и график становится пустым. Возврат к исходному значению в виджете выбора не отображает график, с которого я начал, и остается пустым. Когда я жестко кодирую исходный источник на другой в коде, он отображается нормально, пока я снова не переключу его с помощью виджета, поэтому сами данные, похоже, работают нормально по отдельности.

Я что-то упускаю? Я прочитал много тем, документов и руководств, но не могу найти ничего плохого в своем коде.

Вот что я сделал до сих пор:

Я читаю файл .csv и создаю 3 отдельных фрейма данных, а затем преобразую их в columndatasources. Каждый источник содержит 10 записей данных со столбцами «species», «ci_lower» и «ci_upper». Вот пример одного источника (все три построены точно так же, с разными классами таксонов):

 df = pd.read_csv(os.path.join(os.path.dirname(__file__), "AZA_MLE_Jul2018_utf8.csv",), encoding='utf-8')

m_df = df[df["taxon_class"]=="Mammalia"]
m_df = m_df.sort_values(by="mle", ascending=False)
m_df = m_df.reset_index(drop=True)
m_df = m_df.head(10)
m_df = m_df.sort_values(by="species", ascending=False)
m_df = m_df.reset_index(drop=True)
m_source = bp.ColumnDataSource(m_df)
  

Я сохранил все 3 источника в dict:

 sources_dict={
    "Mammalia": m_source,
    "Aves": a_source,
    "Reptilia": r_source
}
  

… и затем создал мою переменную с именем «source», которая должна изменяться в интерактивном режиме с источником «Mammalia» по умолчанию:

 source = sources_dict["Mammalia"]
  

Затем я создал фигуру и добавил график hbar с исходной переменной следующим образом:

 plot = bp.figure(x_range=(0, np.amax(source.data["ci_upper"]) 5), y_range=source.data["species"])

plot.hbar(y="species", right="ci_lower", left="ci_upper", height=0.5, fill_color="#b3de69", source=source)
  

Затем я добавил виджет выбора с обратным вызовом python:

 def select_handler(attr, old, new):
    source.data["species"]=sources_dict[new].data["species"]
    source.data["ci_lower"]=sources_dict[new].data["ci_lower"]
    source.data["ci_upper"]=sources_dict[new].data["ci_upper"]

select = Select(title="Taxonomic Class:", value="Mammalia", options=list(sources_dict.keys()))
select.on_change("value", select_handler)
curdoc().add_root(bk.layouts.row(plot, select))
  

Я попробовал это:

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

Я попытался использовать собственный словарь python:

 new_data= {
        'species': sources_dict[new].data["species"],
        'ci_lower': sources_dict[new].data["ci_lower"],
        'ci_upper': sources_dict[new].data["ci_upper"]
    }
    source.data=new_data
  

Я попытался назначить весь источник данных, а не просто поменять местами данные

 source=sources_dict[new]
  

Я также пытался использовать dict()

 source.data = dict(species=sources_dict[new].data["species"], ci_lower=sources_dict[new].data["ci_lower"], ci_upper=sources_dict[new].data["ci_upper"])
  

Скриншоты

Вот скриншот начального графика, когда я запускаю файл py с помощью bokeh serve —show file.py

начальный график

И здесь один после изменения выбранного значения:

после переключения

Было бы очень полезно использовать любые подсказки, которые могли бы помочь мне разобраться в этом

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

1. На первый взгляд кажется, что основной причиной являются диапазоны фигуры — вы устанавливаете их статически, но никогда не обновляете их. Если это не так, пожалуйста, предоставьте код в виде одного блока — разделение его на несколько неполных разделов делает его практически невозможным для воспроизведения. Пожалуйста, также предоставьте хотя бы некоторые примеры данных. Другими словами, требуется минимальный воспроизводимый пример.

2. Интересно, так что запись y_range=source.data["species"] на рисунке, а затем в обратном вызове изменение source.data[«species»] также не изменяет y_range? Как бы мне запустить «перечитывание» источника для фигуры?

Ответ №1:

Отвечая на ваш вопрос в комментарии, изменение data не изменяет диапазоны, потому y_range=some_thing что это просто удобство по сравнению с созданием правильного класса диапазона, который выполняется за кулисами.

Вот как вы можете сделать это вручную. Обратите внимание, что я вообще не трогаю x_range — по умолчанию он DataRange1d автоматически вычисляет свои начальные / конечные значения.

 from bokeh.io import curdoc
from bokeh.layouts import column
from bokeh.models import Select, ColumnDataSource
from bokeh.plotting import figure

d1 = dict(x=[0, 1], y=['a', 'b'])
d2 = dict(x=[8, 9], y=['x', 'y'])
ds = ColumnDataSource(d1)


def get_factors(data):
    return sorted(set(data['y']))


p = figure(y_range=get_factors(d1))
p.circle(x='x', y='y', source=ds)

s = Select(options=['1', '2'], value='1')


def update(attr, old, new):
    if new == '1':
        ds.data = d1
    else:
        ds.data = d2
    p.y_range.factors = get_factors(ds.data)


s.on_change('value', update)

curdoc().add_root(column(p, s))
  

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

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