tpaviot / pythonocc-core

Python package for 3D geometry CAD/BIM/CAM
GNU Lesser General Public License v3.0
1.38k stars 380 forks source link

[JupyterRenderer]: TraitError: The 'rotation' trait of a GridHelper instance contains an Enum of an Euler which expected any of ['XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX'], not the str 'xyz'. #1358

Open SGR-FA opened 3 months ago

SGR-FA commented 3 months ago

Hi,

First of all, thank you all for your great work !!

I'm upgrading from an old Python 3.8 venv but unfortunately I get this message when I try to open a viewer in my notebooks. For now, I'm completely stuck but as I understood, the "XYZ" value of the Euler rotation gets lowercased somewhere during the Jupyter traits/session/zmqstream/socket communication. It could be during any of the cast, from_json, to_json, send_multipart or recv_multipart steps but I have not managed to find which one :( and I get the same TraitError for any other version of python/occt/ifcopenshell...

Does anyone also experience this or did I miss something?

Here is the venv :

#conda env export --from-history

name: ifc_viewer_311
channels:
  - defaults
dependencies:
  - pythonocc-core[build=*novtk*]
  - lark
  - occt=7.7.2
  - ifcopenshell
  - python=3.11
  - jsonpath-ng
  - pythreejs
  - vpython
  - cmasher
  - ipywidgets
  - ipympl
  - matplotlib
  - traitlets
  - jupyterlab
  - scipy
  - pandas
  - tornado

Here is an example to get the error:

import ifcopenshell
import ifcopenshell.geom

settings = ifcopenshell.geom.settings()
settings.set(settings.USE_PYTHON_OPENCASCADE, True)

from OCC.Display.WebGl.jupyter_renderer import JupyterRenderer as Renderer

class ifc_viewer(Renderer):
    def __init__(self):
        Renderer.__init__(self)
        self.products = []

    @staticmethod
    def subshapes(shp):
        import OCC.Core.TopoDS
        it = OCC.Core.TopoDS.TopoDS_Iterator(shp)
        while it.More():
            yield it.Value()
            it.Next()

    def DisplayShape(self, product, shp, color):
        for shp, sty in zip(self.subshapes(shp), color):
            Renderer.DisplayShape(self, shp, shape_color=sty[0:3], render_edges=True, transparency=True)
            self.products.append(product)

    def onclick(self, item):
        self.html.value = "Selected %r" % self.products[int(item.name)]

file = ifcopenshell.open("YOUR_IFC_FILE.ifc")
geometry = dict((file[item.data.id], (item.geometry, item.styles)) for item in ifcopenshell.geom.iterator(settings, file))

viewer = ifc_viewer()

for product, (shape, styles) in geometry.items():
    viewer.DisplayShape(product, shape, styles)

viewer.Display()

Here is the output

---------------------------------------------------------------------------
TraitError                                Traceback (most recent call last)
File D:\Anaconda3\envs\ifc_viewer_311\Lib\site-packages\ipywidgets\widgets\widget.py:773, in Widget._handle_msg(self, msg)
    771         if 'buffer_paths' in data:
    772             _put_buffers(state, data['buffer_paths'], msg['buffers'])
--> 773         self.set_state(state)
    775 # Handle a state request.
    776 elif method == 'request_state':

File D:\Anaconda3\envs\ifc_viewer_311\Lib\site-packages\ipywidgets\widgets\widget.py:655, in Widget.set_state(self, sync_data)
    652 if name in self.keys:
    653     from_json = self.trait_metadata(name, 'from_json',
    654                                     self._trait_from_json)
--> 655     self.set_trait(name, from_json(sync_data[name], self))

File D:\Anaconda3\envs\ifc_viewer_311\Lib\site-packages\traitlets\traitlets.py:1764, in HasTraits.set_trait(self, name, value)
   1762 if not self.has_trait(name):
   1763     raise TraitError(f"Class {cls.__name__} does not have a trait named {name}")
-> 1764 getattr(cls, name).set(self, value)

File D:\Anaconda3\envs\ifc_viewer_311\Lib\site-packages\traitlets\traitlets.py:690, in TraitType.set(self, obj, value)
    689 def set(self, obj: HasTraits, value: S) -> None:
--> 690     new_value = self._validate(obj, value)
    691     assert self.name is not None
    692     try:

File D:\Anaconda3\envs\ifc_viewer_311\Lib\site-packages\traitlets\traitlets.py:722, in TraitType._validate(self, obj, value)
    720     return value
    721 if hasattr(self, "validate"):
--> 722     value = self.validate(obj, value)
    723 if obj._cross_validation_lock is False:
    724     value = self._cross_validate(obj, value)

File D:\Anaconda3\envs\ifc_viewer_311\Lib\site-packages\traitlets\traitlets.py:3482, in Container.validate(self, obj, value)
   3479 if value is None:
   3480     return value
-> 3482 value = self.validate_elements(obj, value)
   3484 return t.cast(T, value)

File D:\Anaconda3\envs\ifc_viewer_311\Lib\site-packages\traitlets\traitlets.py:3823, in Tuple.validate_elements(self, obj, value)
   3821     v = trait._validate(obj, v)
   3822 except TraitError as error:
-> 3823     self.error(obj, v, error)
   3824 else:
   3825     validated.append(v)

File D:\Anaconda3\envs\ifc_viewer_311\Lib\site-packages\traitlets\traitlets.py:810, in TraitType.error(self, obj, value, error, info)
    801         else:
    802             error.args = (
    803                 "The '{}' trait contains {} which " "expected {}, not {}.".format(
    804                     self.name,
   (...)
    808                 ),
    809             )
--> 810     raise error
    812 # this trait caused an error
    813 if self.name is None:
    814     # this is not the root trait

File D:\Anaconda3\envs\ifc_viewer_311\Lib\site-packages\traitlets\traitlets.py:3821, in Tuple.validate_elements(self, obj, value)
   3819 for trait, v in zip(self._traits, value):
   3820     try:
-> 3821         v = trait._validate(obj, v)
   3822     except TraitError as error:
   3823         self.error(obj, v, error)

File D:\Anaconda3\envs\ifc_viewer_311\Lib\site-packages\traitlets\traitlets.py:722, in TraitType._validate(self, obj, value)
    720     return value
    721 if hasattr(self, "validate"):
--> 722     value = self.validate(obj, value)
    723 if obj._cross_validation_lock is False:
    724     value = self._cross_validate(obj, value)

File D:\Anaconda3\envs\ifc_viewer_311\Lib\site-packages\traitlets\traitlets.py:3224, in Enum.validate(self, obj, value)
   3222 if self.values and value in self.values:
   3223     return t.cast(G, value)
-> 3224 self.error(obj, value)

File D:\Anaconda3\envs\ifc_viewer_311\Lib\site-packages\traitlets\traitlets.py:815, in TraitType.error(self, obj, value, error, info)
    812 # this trait caused an error
    813 if self.name is None:
    814     # this is not the root trait
--> 815     raise TraitError(value, info or self.info(), self)
    817 # this is the root trait
    818 if obj is not None:

TraitError: The 'rotation' trait of a GridHelper instance contains an Enum of an Euler which expected any of ['XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX'], not the str 'xyz'.

Thank you for your help.

wll0307 commented 1 month ago

TraitError: The 'rotation' trait of a GridHelper instance contains an Enum of an Euler which expected any of ['XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX'], not the str 'xyz'. 我也是这个报错你是用啥解决的

SGR-FA commented 1 month ago

Hi, (please translate, I greatly lack ability to speak/write in this language) Unfortunately, trials and errors forced me to use the rotateX method.

class CustomJupyterRenderer(JupyterRenderer):
...
        self.my_grid = Grid(bb_center=self._bb.center, maximum=bb_max,
                                    colorCenterLine='#aaa', colorGrid='#ddd')
...
        # raises error for now: self.my_grid.set_rotation(((math.pi / 2.0), 0, 0, "XYZ"))
        self.my_grid.grid.rotateX(math.pi / 2.0)
...

BR

SGR-FA commented 2 weeks ago

TraitError: The 'rotation' trait of a GridHelper instance contains an Enum of an Euler which expected any of ['XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX'], not the str 'xyz'. 我也是这个报错你是用啥解决的

FYI, there is an ongoing fix thanks to @vidartf : see issue on jupyter-widgets/pythreejs