Adding variant track does not work
Bug report
unable to add a variant track to an existing browser
Bug summary
Create browser in previous code block. Create track dict for a variant, taking structure from here, though have converted all the field names to strings so as to form a legitimate dictionary. Code block fails with :
TraitError: The 'tracks' trait of an IgvBrowser instance contains which expected <traitlets.traitlets.List object at 0x2aaae2818a90>, not the str 'The "type" trait is read-only.'.
from ipyigv import IgvBrowser as Browser, PUBLIC_GENOMES
from ipyigv.options import Track, ReferenceGenome
genomeToUse = ReferenceGenome(**PUBLIC_GENOMES.hg38)
browser = Browser(genome=genomeToUse)
browser
###################### New code block ####################
trackDict = {
'type': "variant",
'format': "vcf",
'url': "https://s3.amazonaws.com/1000genomes/release/20130502/ALL.chr22.phase3_shapeit2_mvncall_integrated_v5a.20130502.genotypes.vcf.gz",
'indexURL': "https://s3.amazonaws.com/1000genomes/release/20130502/ALL.chr22.phase3_shapeit2_mvncall_integrated_v5a.20130502.genotypes.vcf.gz.tbi",
'name': "1KG variants (chr22)",
'squishedCallHeight': 1,
'expandedCallHeight': 4,
'displayMode': "squished",
'visibilityWindow': 1000
}
Actual outcome
---------------------------------------------------------------------------
TraitError Traceback (most recent call last)
<ipython-input-25-2f6618847406> in <module>
11 }
12
---> 13 browser.add_track(trackDict)
~/.local/lib/python3.8/site-packages/ipyigv/ipyigv.py in add_track(self, track)
72 # List subscript does not work for empty List, so handling this case manually.
73 if len(self.tracks) == 0:
---> 74 self.tracks = [track]
75 else:
76 self.tracks = self.tracks[:] + [track]
~/.local/lib/python3.8/site-packages/traitlets/traitlets.py in __set__(self, obj, value)
602 raise TraitError('The "%s" trait is read-only.' % self.name)
603 else:
--> 604 self.set(obj, value)
605
606 def _validate(self, obj, value):
~/.local/lib/python3.8/site-packages/traitlets/traitlets.py in set(self, obj, value)
576
577 def set(self, obj, value):
--> 578 new_value = self._validate(obj, value)
579 try:
580 old_value = obj._trait_values[self.name]
~/.local/lib/python3.8/site-packages/traitlets/traitlets.py in _validate(self, obj, value)
608 return value
609 if hasattr(self, 'validate'):
--> 610 value = self.validate(obj, value)
611 if obj._cross_validation_lock is False:
612 value = self._cross_validate(obj, value)
~/.local/lib/python3.8/site-packages/traitlets/traitlets.py in validate(self, obj, value)
2498 return value
2499
-> 2500 value = self.validate_elements(obj, value)
2501
2502 return value
~/.local/lib/python3.8/site-packages/traitlets/traitlets.py in validate_elements(self, obj, value)
2637 self.length_error(obj, value)
2638
-> 2639 return super(List, self).validate_elements(obj, value)
2640
2641
~/.local/lib/python3.8/site-packages/traitlets/traitlets.py in validate_elements(self, obj, value)
2510 v = self._trait._validate(obj, v)
2511 except TraitError as error:
-> 2512 self.error(obj, v, error)
2513 else:
2514 validated.append(v)
~/.local/lib/python3.8/site-packages/traitlets/traitlets.py in error(self, obj, value, error, info)
674 "expected %s, not %s." % (self.name, chain,
675 error.args[1], describe("the", error.args[0])),)
--> 676 raise error
677 else:
678 # this trait caused an error
~/.local/lib/python3.8/site-packages/traitlets/traitlets.py in validate_elements(self, obj, value)
2508 for v in value:
2509 try:
-> 2510 v = self._trait._validate(obj, v)
2511 except TraitError as error:
2512 self.error(obj, v, error)
~/.local/lib/python3.8/site-packages/traitlets/traitlets.py in _validate(self, obj, value)
608 return value
609 if hasattr(self, 'validate'):
--> 610 value = self.validate(obj, value)
611 if obj._cross_validation_lock is False:
612 value = self._cross_validate(obj, value)
~/.local/lib/python3.8/site-packages/ipywidgets/widgets/trait_types.py in validate(self, obj, value)
161 def validate(self, obj, value):
162 if isinstance(value, dict):
--> 163 return super(InstanceDict, self).validate(obj, self.klass(**value))
164 else:
165 return super(InstanceDict, self).validate(obj, value)
~/.local/lib/python3.8/site-packages/ipywidgets/widgets/widget.py in __init__(self, **kwargs)
410 """Public constructor"""
411 self._model_id = kwargs.pop('model_id', None)
--> 412 super(Widget, self).__init__(**kwargs)
413
414 Widget._call_widget_constructed(self)
~/.local/lib/python3.8/site-packages/traitlets/traitlets.py in __init__(self, *args, **kwargs)
1075 for key, value in kwargs.items():
1076 if self.has_trait(key):
-> 1077 setattr(self, key, value)
1078 else:
1079 # passthrough args that don't set traits to super
~/.local/lib/python3.8/site-packages/traitlets/traitlets.py in __set__(self, obj, value)
600 """
601 if self.read_only:
--> 602 raise TraitError('The "%s" trait is read-only.' % self.name)
603 else:
604 self.set(obj, value)
TraitError: The 'tracks' trait of an IgvBrowser instance contains which expected <traitlets.traitlets.List object at 0x2aaae2818a90>, not the str 'The "type" trait is read-only.'.
Expected outcome
A track added to the browser
Version Info jupyter lab 2.2.4 python 3.8.1
As an addendum, if one removes the trait entry from the dict, then the error changes to:
TraitError: The 'tracks' trait of an IgvBrowser instance contains which expected <traitlets.traitlets.List object at 0x2aaae2814520>, not the str "The 'color' trait of a VariantTrack instance expected a valid HTML color, not the Sentinel traitlets.Undefined.".
No further modifications change the error message, which is in full:
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
~/.local/lib/python3.8/site-packages/traitlets/traitlets.py in get(self, obj, cls)
534 try:
--> 535 value = obj._trait_values[self.name]
536 except KeyError:
KeyError: 'color'
During handling of the above exception, another exception occurred:
TraitError Traceback (most recent call last)
<ipython-input-18-4863a6327e30> in <module>
5 }
6
----> 7 browser.add_track(trackDict)
~/.local/lib/python3.8/site-packages/ipyigv/ipyigv.py in add_track(self, track)
72 # List subscript does not work for empty List, so handling this case manually.
73 if len(self.tracks) == 0:
---> 74 self.tracks = [track]
75 else:
76 self.tracks = self.tracks[:] + [track]
~/.local/lib/python3.8/site-packages/traitlets/traitlets.py in __set__(self, obj, value)
602 raise TraitError('The "%s" trait is read-only.' % self.name)
603 else:
--> 604 self.set(obj, value)
605
606 def _validate(self, obj, value):
~/.local/lib/python3.8/site-packages/traitlets/traitlets.py in set(self, obj, value)
576
577 def set(self, obj, value):
--> 578 new_value = self._validate(obj, value)
579 try:
580 old_value = obj._trait_values[self.name]
~/.local/lib/python3.8/site-packages/traitlets/traitlets.py in _validate(self, obj, value)
608 return value
609 if hasattr(self, 'validate'):
--> 610 value = self.validate(obj, value)
611 if obj._cross_validation_lock is False:
612 value = self._cross_validate(obj, value)
~/.local/lib/python3.8/site-packages/traitlets/traitlets.py in validate(self, obj, value)
2498 return value
2499
-> 2500 value = self.validate_elements(obj, value)
2501
2502 return value
~/.local/lib/python3.8/site-packages/traitlets/traitlets.py in validate_elements(self, obj, value)
2637 self.length_error(obj, value)
2638
-> 2639 return super(List, self).validate_elements(obj, value)
2640
2641
~/.local/lib/python3.8/site-packages/traitlets/traitlets.py in validate_elements(self, obj, value)
2510 v = self._trait._validate(obj, v)
2511 except TraitError as error:
-> 2512 self.error(obj, v, error)
2513 else:
2514 validated.append(v)
~/.local/lib/python3.8/site-packages/traitlets/traitlets.py in error(self, obj, value, error, info)
674 "expected %s, not %s." % (self.name, chain,
675 error.args[1], describe("the", error.args[0])),)
--> 676 raise error
677 else:
678 # this trait caused an error
~/.local/lib/python3.8/site-packages/traitlets/traitlets.py in validate_elements(self, obj, value)
2508 for v in value:
2509 try:
-> 2510 v = self._trait._validate(obj, v)
2511 except TraitError as error:
2512 self.error(obj, v, error)
~/.local/lib/python3.8/site-packages/traitlets/traitlets.py in _validate(self, obj, value)
608 return value
609 if hasattr(self, 'validate'):
--> 610 value = self.validate(obj, value)
611 if obj._cross_validation_lock is False:
612 value = self._cross_validate(obj, value)
~/.local/lib/python3.8/site-packages/ipywidgets/widgets/trait_types.py in validate(self, obj, value)
161 def validate(self, obj, value):
162 if isinstance(value, dict):
--> 163 return super(InstanceDict, self).validate(obj, self.klass(**value))
164 else:
165 return super(InstanceDict, self).validate(obj, value)
~/.local/lib/python3.8/site-packages/ipywidgets/widgets/widget.py in __init__(self, **kwargs)
413
414 Widget._call_widget_constructed(self)
--> 415 self.open()
416
417 def __del__(self):
~/.local/lib/python3.8/site-packages/ipywidgets/widgets/widget.py in open(self)
426 """Open a comm to the frontend if one isn't already open."""
427 if self.comm is None:
--> 428 state, buffer_paths, buffers = _remove_buffers(self.get_state())
429
430 args = dict(target_name='jupyter.widget',
~/.local/lib/python3.8/site-packages/ipywidgets/widgets/widget.py in get_state(self, key, drop_defaults)
516 for k in keys:
517 to_json = self.trait_metadata(k, 'to_json', self._trait_to_json)
--> 518 value = to_json(getattr(self, k), self)
519 if not PY3 and isinstance(traits[k], Bytes) and isinstance(value, bytes):
520 value = memoryview(value)
~/.local/lib/python3.8/site-packages/traitlets/traitlets.py in __get__(self, obj, cls)
573 return self
574 else:
--> 575 return self.get(obj, cls)
576
577 def set(self, obj, value):
~/.local/lib/python3.8/site-packages/traitlets/traitlets.py in get(self, obj, cls)
546 )
547 with obj.cross_validation_lock:
--> 548 value = self._validate(obj, default)
549 obj._trait_values[self.name] = value
550 obj._notify_observers(Bunch(
~/.local/lib/python3.8/site-packages/traitlets/traitlets.py in _validate(self, obj, value)
608 return value
609 if hasattr(self, 'validate'):
--> 610 value = self.validate(obj, value)
611 if obj._cross_validation_lock is False:
612 value = self._cross_validate(obj, value)
~/.local/lib/python3.8/site-packages/ipywidgets/widgets/trait_types.py in validate(self, obj, value)
50 return value
51
---> 52 self.error(obj, value)
53
54
~/.local/lib/python3.8/site-packages/traitlets/traitlets.py in error(self, obj, value, error, info)
688 e = "The '%s' trait expected %s, not %s." % (
689 self.name, self.info(), describe("the", value))
--> 690 raise TraitError(e)
691
692 def get_metadata(self, key, default=None):
TraitError: The 'tracks' trait of an IgvBrowser instance contains which expected <traitlets.traitlets.List object at 0x2aaae2814520>, not the str "The 'color' trait of a VariantTrack instance expected a valid HTML color, not the Sentinel traitlets.Undefined.".
I just ran into the same error, did you ever find a fix or workaround?
Ah! Checked the v1.0 API doc and found that adding 'color': "#000000" to the track dictionary made the track appear!