python - 在主轴上的 vbar_stacked 图和次轴上的线图的图中,主要 y_range 不会更新
问题描述
我正在 Bokeh 上同时绘制 vbar_stacked 和线图,主 y 轴上的条形图和辅助轴上的线。该图工作正常,当使用选项按钮更新数据时,数据会相应更改,辅助轴也会发生变化,但主轴保持不变。
######## 1. Importing
import pandas as pd
from bokeh.io import curdoc
from bokeh.layouts import row
from bokeh.palettes import Category20c
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource, Select, LinearAxis, Range1d
######## 2. A poor fictional data example
df=pd.DataFrame({'Col1':[45101.023283,41381.466914,7668.987818,
4682.412413,4677.391936, 4668.987818],
'Col2':[35101.023283,51381.466914,5668.987818,
3682.412413,4677.391936, 3668.987818]})
df['Col3']=3*df['Col1']
df['ID_group']='A'
df['ID_group'][3:]='B'
df['ID_sim']=['a','b','c','d','e','f']
df=df.set_index(['ID_group','ID_sim'])
# Defining the col for bar plotting
col_bars=['Col1','Col2']
#Defining the cols for line plotting
col_line='Col3'
######## 3. The excerpt extracted from my original code
### Segmentar o DF para Transformacao em Dados de Torta
df_plot=df.loc['A']
### Convertendo o df_plot em ColumnDataSource
source=ColumnDataSource(df_plot)
### Criacao da Figura para Plot, com coluna_categoria como eixo x
p = figure(x_range=list(df_plot.index))
### ColorMap para Cores da Legenda
cmap=Category20c[20][:len(col_bars)]
### Plot das Colunas
barra = p.vbar_stack(col_bars, x='ID_sim', width=0.9,source=source,
color=cmap, line_color='black', line_width=0.6)
### Impondo o limite minimo do eixo y
p.y_range.start=0
### Impondo o limite máxximo do eixo y
p.y_range.end=max(df_plot[col_bars].sum(axis=1))*1.1
### Caso coluna_linha nao seja vazio,inserir plot secundario
if list(col_line):
### Definir eixo secundario
p.extra_y_ranges={'y_secundario':Range1d(start=0,
end=float(df_plot[col_line].sum().max())*1.1)}
### Adicionar o eixo ao layout
p.add_layout(LinearAxis(y_range_name='y_secundario'),'right')
### Plotar a coluna_linha
linha = p.line(x='ID_sim',y=col_line,source=source,
color='firebrick',y_range_name='y_secundario')
### Plotando o marcador da linha
circulo = p.circle(x='ID_sim',y=col_line,source=source,color='firebrick',
fill_color='white',size=10,y_range_name='y_secundario')
### Criacao do Dropbox Menu para Selecao do Conjunto de Analise
select_option = Select(title='ID',
options=['A','B'], value='A')
### Criacao de Callback que atualiza o plot conforme selecao do menu select_conjunto
def update_plot(attr,old,new):
### Coleta do valor selecionado no menu select_conjunto
conjunto = select_option.value
### Resegmentar o DF para Transformacao em Dados de Torta
df_plot=df.loc[conjunto]
### Atualizando os dados do plot
source.data={i:df_plot.reset_index()[i] for i in df_plot.reset_index().columns}
### Atualizando o eixo de categorias
p.x_range.factors=list(df_plot.index)
### Atualizando o eixo y principal
p.y_range.end=max(df_plot[col_bars].sum(axis=1))*1.1
### Atualizando eixo y secundário
p.extra_y_ranges['y_secundario'].end=max(df_plot[col_line])*1.1
select_option.on_change('value',update_plot)
### Criacao do Layout com o Grafico e os Menus
layout=row(p,select_option,sizing_mode='stretch_width')
curdoc().add_root(layout)
一切正常,除了屏幕中 y_range 的变化......当我打印 p.y_range.end 值时,它应该是......
解决方案
因此,我认为与默认 y 范围存在某种奇怪的交互,因为它是一个 auto-ranging DataRange1d
。如果你设置一个普通的Range1d
:
### Impondo o limite minimo do eixo y
#p.y_range.start=0
### Impondo o limite máxximo do eixo y
#p.y_range.end=max(df_plot[col_bars].sum(axis=1))*1.1
# Do this instead of the above two lines
p.y_range = Range1d(start=0, end=max(df_plot[col_bars].sum(axis=1))*1.1)
然后事情对我有用。