ValueError: expected an element of either Seq(String), Seq(Tuple(String, String)) or Seq(Tuple(String, String, String)),

Hello Community ,
I am new to the community, first time actually.
Due to my lack of experience , I am unable to solve my problem which is the title of this topic.

The short version of hours of reading and sampling , I am unable to figure out the challenges posed.

I am trying to plot a simple line or bar plot to plot the change in a category value over time.

I tried using ,
p = figure(x_axis_type=‘datetime’) #set the plot x axis to read datetime format

I later went back to my data set and added a ID in sequence for each date and used

p= figure(x_range= str(ID)) # set the ID as the range for the x-axis

For both instance the same error has been returned.

So if there is any community member out there that can help me fix my problem I would be very thankful

Below is the code

from bokeh.models import Legend, LegendItem
from bokeh.plotting import figure, output_file, show
from bokeh.models import ColumnDataSource
from bokeh.models.tools import HoverTool

# Import tools for handling multiple columns
from bokeh.palettes import Spectral5
from bokeh.transform import factor_cmap

# Set-up a blank file called ADX at the folder hosting webpages for website
# read the data in the csv file in 
output_file("C:/xampp/htdocs/ADX.html")

#& set the Date column to pandas datetime format
data = pd.read_csv('C:/Users/enda/Desktop/AI-Stock-Prediction-master/BTCEUR.csv',parse_dates=['Date'])

#make sure Date is a  pandas datetime format
data['Date'] = pd.to_datetime(data['Date'], format='%d/%m/%Y')

#Check the Date column is pandas date format

data.tail(10)


#Create ColumnDataSource from Bokeh data frame 
source = ColumnDataSource(data)

# set variable names
ID= str(data["ID"])
ADX = data["ADX"]
Open = data["Open"]
High = data["High"]
Low = data["Low"]


#convert columns to individual lists, Bokeh 
ID = source.data['ID'].tolist()
ADX = source.data['ADX'].tolist()
Open = source.data['Open'].tolist()
High = source.data['High'].tolist()
Low = source.data['Low'].tolist()


#set the plot x axis to read datetime format
p = figure(x_axis_type='datetime')

# set the Date as the range for the x-axis
p= figure(x_range= str(ID))
p.line(x='ID', y='ADX', line_width=2, source=source, legend_label='Measured ADX')


color_map = factor_cmap(field_name='ADX',
                    palette=Spectral5, factors= str(ID))

The error code returned is


ValueError Traceback (most recent call last)
in
52
53
—> 54 color_map = factor_cmap(field_name=‘ADX’,
55 palette=Spectral5, factors= str(ID))
56

C:\ProgramData\Anaconda3\lib\site-packages\bokeh\transform.py in factor_cmap(field_name, palette, factors, start, end, nan_color)
119
120 ‘’’
–> 121 return field(field_name, CategoricalColorMapper(palette=palette,
122 factors=factors,
123 start=start,

C:\ProgramData\Anaconda3\lib\site-packages\bokeh\models\mappers.py in init(self, **kwargs)
139
140 def init(self, **kwargs):
–> 141 super().init(**kwargs)
142 palette = self.palette
143 factors = self.factors

C:\ProgramData\Anaconda3\lib\site-packages\bokeh\models\mappers.py in init(self, palette, **kwargs)
89 if palette is not None:
90 kwargs[‘palette’] = palette
—> 91 super().init(**kwargs)
92
93 @abstract

C:\ProgramData\Anaconda3\lib\site-packages\bokeh\model.py in init(self, **kwargs)
232 kwargs.pop(“id”, None)
233
–> 234 super().init(**kwargs)
235 default_theme.apply_to_model(self)
236

C:\ProgramData\Anaconda3\lib\site-packages\bokeh\core\has_props.py in init(self, **properties)
245
246 for name, value in properties.items():
–> 247 setattr(self, name, value)
248
249 def setattr(self, name, value):

C:\ProgramData\Anaconda3\lib\site-packages\bokeh\core\has_props.py in setattr(self, name, value)
272
273 if name in props or (descriptor is not None and descriptor.fset is not None):
–> 274 super().setattr(name, value)
275 else:
276 matches, text = difflib.get_close_matches(name.lower(), props), “similar”

C:\ProgramData\Anaconda3\lib\site-packages\bokeh\core\property\descriptors.py in set(self, obj, value, setter)
537 raise RuntimeError("%s.%s is a readonly property" % (obj.class.name, self.name))
538
–> 539 self._internal_set(obj, value, setter=setter)
540
541 def delete(self, obj):

C:\ProgramData\Anaconda3\lib\site-packages\bokeh\core\property\descriptors.py in _internal_set(self, obj, value, hint, setter)
758
759 ‘’’
–> 760 value = self.property.prepare_value(obj, self.name, value)
761
762 old = self.get(obj, obj.class)

C:\ProgramData\Anaconda3\lib\site-packages\bokeh\core\property\bases.py in prepare_value(self, obj_or_cls, name, value)
329 break
330 else:
–> 331 raise e
332 else:
333 value = self.transform(value)

C:\ProgramData\Anaconda3\lib\site-packages\bokeh\core\property\bases.py in prepare_value(self, obj_or_cls, name, value)
322 try:
323 if validation_on():
–> 324 self.validate(value)
325 except ValueError as e:
326 for tp, converter in self.alternatives:

C:\ProgramData\Anaconda3\lib\site-packages\bokeh\core\property\either.py in validate(self, value, detail)
107 if not (value is None or any(param.is_valid(value) for param in self.type_params)):
108 msg = “” if not detail else “expected an element of either %s, got %r” % (nice_join(self.type_params), value)
–> 109 raise ValueError(msg)
110
111 # TODO (bev) implement this

ValueError: expected an element of either Seq(String), Seq(Tuple(String, String)) or Seq(Tuple(String, String, String)), got ‘[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, …558, 559, 560, 561]’

Apologies, I forgot to include a sample of the dataset

ID Date Open High Low Close ADX
551 2020-11-17 14102.59 15067.65 13969.99 14887.12 24.981879
552 2020-11-18 14886.49 15551.69 14500.00 15012.85 27.357023
553 2020-11-19 15012.96 15362.71 14680.02 15032.93 25.356301
554 2020-11-20 15024.09 15875.14 14978.00 15735.55 28.335320
555 2020-11-21 15724.20 15979.00 15523.00 15752.56 28.063857
560 2020-11-26 15717.96 15852.00 11400.00 13838.96| -16.848101|

1 Like

Hi @Enda_Keane,

Can you clarify what you want the end result to look like? Your code sample creates a single line renderer, but the colormap (which is where it’s breaking, it doesn’t like the factors argument) suggests to me that maybe you want multiple lines, with one line/color per ID?

I’ve been experimenting, and I don’t think CategoricalColorMapper will work with p.line. (I could be wrong, and I invite any other team members to correct me if so, but I haven’t gotten it to work yet.)

If you are indeed just looking to create a timeseries plot with one line per data column, then you could do something like this:

import pandas as pd
from bokeh.plotting import figure, output_file, show
from bokeh.models import ColumnDataSource

# Import tools for handling multiple columns
from bokeh.palettes import Spectral5

# Set-up a blank file called ADX at the folder hosting webpages for website
# read the data in the csv file in
#output_file("C:/xampp/htdocs/ADX.html")

# change back to your data source location
data = pd.read_csv('cmap_question_data.csv', parse_dates=['Date'])

#make sure Date is a  pandas datetime format
data['Date'] = pd.to_datetime(data['Date'], format='%d/%m/%Y')

#Check the Date column is pandas date format
data.tail(10)

#Create ColumnDataSource from pandas data frame
source = ColumnDataSource(data)

#set the plot x axis to read datetime format
p = figure(x_axis_type='datetime', width=800, height=300)

# set the Date as the range for the x-axis
p.line(x='Date', y='Open', line_width=2, source=source, legend_label='Open', color=Spectral5[0])
p.line(x='Date', y='High', line_width=2, source=source, legend_label='High', color=Spectral5[1])
p.line(x='Date', y='Close', line_width=2, source=source, legend_label='Close', color=Spectral5[2])
p.line(x='Date', y='Low', line_width=2, source=source, legend_label='Low', color=Spectral5[3])
p.line(x='Date', y='ADX', line_width=2, source=source, legend_label='Measured ADX', color=Spectral5[4])

show(p)

You mention the possibility of a bar chart, though, which would be different; then the colormapper might be of more use.

This is correct. The p.line method draws one single line, which is always and only one color along its entire length (i.e., there is nothing to colormap). A color mapper could be used with multi_line to map a different color for each of the multiple lines.

1 Like

Hi ,
Thanks for the response,
The intend of my data is to have 2 lines
I am looking to add a second line that intersects at 0 ( baseline ) across the data set, the ADX values are 2nd line

Hi Carolyn and Brian ,
thanks for the input ,
I will clarify my original question ,

I have a data set , that I wish to plot. In my head there were two options,
to use the ADX dataset as the y dataset , and Date or ID as the x data set. Once working I intended to add a reference line = 0. From the sample data I supplied , the ADX can be a_-ve or +ve value. So I would be showing the ADX crossing 0 when its value changes over time.

As I said in my head I planned on plotting with either of

  1. Multi Line , for which I am attempting to use the multi-line
    example code I am working off from
    Preformatted textVisualizing Data with Bokeh and Pandas | Programming Historian

  2. if possible use the ADX as a box and 0 as a line in this 2nd case.

Hi Core Team members ,

Thank you for your inputs , I changes how I present the data.
For the ADX values , I replaced p.line with p.circle.
I added a baseline = 0 to the dataset .

When replotted in Bokeh, I got a result I that I can live with - circles plotted about 0

When I plot using p.line it returns squiggly lines, not what I was looking for . it looks like the plot is rendering by lowest value causing a not so beautiful plot.

CODE
import pandas as pd
from bokeh.plotting import figure, output_file, show
from bokeh.models import ColumnDataSource

# Import tools for handling multiple columns
from bokeh.palettes import Spectral5

# Set-up a blank file called ADX at the folder hosting webpages for website
# read the data in the csv file in
#output_file("C:/xampp/htdocs/ADX.html")

# change back to your data source location
data = pd.read_csv('C:/Users/enda/Desktop/AI-Stock-Prediction-master/BTCEUR.csv',parse_dates=['Date'])

#make sure Date is a  pandas datetime format
data['Date'] = pd.to_datetime(data['Date'], format='%d/%m/%Y')

#Check the Date column is pandas date format
data.tail(10)

#Create ColumnDataSource from pandas data frame
source = ColumnDataSource(data)

#set the plot x axis to read datetime format
p = figure(x_axis_type='datetime', width=800, height=300)

# set the Date as the range for the x-axis
#p.line(x='Date', y='Open', line_width=2, source=source, legend_label='Open', color=Spectral5[0])
#p.line(x='Date', y='High', line_width=2, source=source, legend_label='High', color=Spectral5[1])
#p.line(x='Date', y='Close', line_width=2, source=source, legend_label='Close', color=Spectral5[2])
#p.line(x='Date', y='Low', line_width=2, source=source, legend_label='Low', color=Spectral5[3])
p.circle(x='Date', y='ADX', line_width=2, source=source, legend_label='Measured ADX', color=Spectral5[4])
p.line(x='Date', y='Baseline', line_width=2, source=source, legend_label='Baseline', color=Spectral5[0])

show(p)

New Dataset Sample

ID Date Open High Low Close ADX Baseline
1 16/05/2019 7325.96 7468.35 6862.01 7055 30.58482141 0
2 17/05/2019 7055.01 7097.99 6000 6607.41 11.37121472 0
3 18/05/2019 6608.4 6749 6474.81 6540.01 10.85698195 0
4 19/05/2019 6540 7438.42 6522.1 7348.33 19.86859006 0
5 20/05/2019 7340.04 7346.13 6810 7164.12 18.25219923 0

A Shout out to you and the community support team,
Thank you once again for your insights,

Regards
Enda

1 Like

@Enda_Keane,

That looks really good, and easy to understand! I’m glad you came up with something that works for you and your data. :slight_smile: