0

I'm doing a Bokeh application in which I have an input table, some calculations are performed on it and it produces a new table. I'm trying to plot a heatmap of this new table, so I have to create a colorbar using the LinearColorMapper function, however I can't use the min and max values from the calculated table (which is a ColumnDataSource), this is how the table is stored:

def val_portafolio_mostrar():
  val_portafolio=datos_calcular()
  val_mapa=pd.DataFrame(val_portafolio.stack(), columns=['valoracion']).reset_index()
  datos_heatmap.data=dict(val_mapa)

The values which are going to be plotted on the heatmap are in the 'valoracion' column from datos_heatmap, this is the code I'm using for the LinearColorMapper

colors = ["#75968f", "#a5bab7", "#c9d9d3", "#e2e2e2", "#dfccce", "#ddb7b1", "#cc7878", "#933b41", "#550b1d"]
mapper = LinearColorMapper(palette=colors, low=min(datos_heatmap.data['valoracion']), 
                            high=max(datos_heatmap.data['valoracion']))

however I'm getting the following error:

in mapper_fun
    mapper = LinearColorMapper(palette=colors, low=min(datos_heatmap.data['valoracion']),
ValueError: min() arg is an empty sequence

I think it's because in order to access a ColumnDataSource value, the function needs to have the "source" parameter, however the LinearColorMapper function does not have this parameter so it's not possible to solve it this way. I also tried to store the max and min values in another ColumnDataSource but I get the same error because I'm not using a source rather just extracting the values as in "datos_heatmap.data['valoracion']"

Thanks in advance!

andrespm
  • 23
  • 5

1 Answers1

0

I guess the problem is, that your datos_heatmap.data['valoracion'] really is an empty sequence. Please provide futher information here with a minimal example and try printing your datos_heatmap.data['valoracion'] right before you pass it to the LinearColorMapper. If you work with python functions, make sure that your definitions are correct within the namespaces you want them to exist.
Check the following example, that works the same way as you want it to:

import pandas as pd
from bokeh.plotting import figure, show
from bokeh.models import ColumnDataSource, LinearColorMapper
from bokeh.layouts import layout

plot1 = figure(plot_width=1000, plot_height=250)

df = pd.DataFrame({"ID":[0, 1, 2, 3], 
                   "Value1":[0, 100, 200, 300]})

source = ColumnDataSource(df)

cmap = LinearColorMapper(palette="Turbo256", low = min(source.data["Value1"]), high = max(source.data["Value1"]))

print(f"high value cmap: {cmap.high}")
print(f"low value cmap: {cmap.low}")

circle = plot1.circle(x='ID', y='Value1', source=source, size=30,
                      fill_color={"field":'Value1', "transform":cmap})

show(plot1)

This produces the following plot: enter image description here

Crysers
  • 455
  • 2
  • 13
  • datos_heatmap.data['valoracion'] comes from datos_calcular() which is a large function, that's why I didn't put in the question. Also, I use datos_heatmap as a source for a line glyph so it isn't an empty sequence. I think the problem is that LinearColorMapper doesn't have a "source" argument so I can't use the ColumnDataSource content. – andrespm Mar 24 '21 at 19:51
  • As you see in my Code example, there is also no source argument. The source is only used to calculate the min() and max() value of that column. So there is no need for an argument that handles the source itself. You only pass a value to `low` and `high`. What is the output of `print()` when you put `print(min(datos_heatmap.data['valoracion']))` exactly one line above your `mapper = LinearColorMapper(palette=colors, low=min(datos_heatmap.data['valoracion']), high=max(datos_heatmap.data['valoracion']))` ? – Crysers Mar 25 '21 at 08:19