Skip to content

Docs

compound

Compound

Bases: Vizr3D, Network

material along with properties

Source code in molvizr3d/docs/compound.py
class Compound(Vizr3D, Network):
    '''
    material along with properties
    '''
    _mat_cid = ''
    _mat_name = ''
    _mat_formula = ''
    _atom_numbers = 0
    _atom_elements = []
    _atom_xyz = []
    _atom_xyz_center = []
    _atom_bond_block = []
    _atom_bond_numbers = 0

    # *** obs fixed ***
    _limits = {
        'phi': [],
        'teta': [np.deg2rad(0), np.deg2rad(180)]
    }
    _robs = 10
    _tetaNo = OBSERVER_PROPERTY.get('TETA')
    _phiNo = OBSERVER_PROPERTY.get('PHI')
    _dataNo = []
    _obsCoordinate = []

    def __init__(self, parse_prop):
        # all properties
        self.parse_prop = parse_prop
        # super class
        __atom_elements = parse_prop['atom_elements']
        __atom_bonds = parse_prop['bond_block']
        __atom_xyz = parse_prop['xyz_list']
        __atom_xyz_center = parse_prop['xyz_center_list']
        # limit
        __limits = self._limits

        # TODO: convert atom_bonds to 1d vector
        __atom_bonds_1d = self.convert_atom_bonds(__atom_bonds)

        # ! init parent classes
        # *** raw info (just for visualizing a structure)
        Vizr3D.__init__(self, __atom_elements, __atom_bonds,
                        __atom_xyz, __atom_xyz_center, self.robs, self.tetaNo, self.phiNo, __limits)

        # *** network
        Network.__init__(self, __atom_elements, __atom_bonds,
                         __atom_xyz, __atom_xyz_center, __atom_bonds_1d)

        # update mat prop
        self.__update_atom_prop('mat_cid')
        self.__update_atom_prop('mat_name')
        self.__update_atom_prop('mat_formula')
        self.__update_atom_prop('atom_numbers')
        self.__update_atom_prop('atom_elements')
        self.__update_atom_prop('bond_numbers')
        self.__update_atom_prop('bond_block')
        self.__update_atom_prop('xyz_list')
        self.__update_atom_prop('xyz_center_list')

    def __str__(self):
        '''
        Return info about the mat
        '''
        # check
        if self.parse_prop['mat_name'] is not None:
            return str(self.parse_prop['mat_name'])
        else:
            return str(self.parse_prop['atom_elements'])

    @property
    def mat_cid(self):
        return self.parse_prop['mat_cid']

    @mat_cid.setter
    def mat_cid(self, value):
        self._mat_cid = value

    @property
    def mat_name(self):
        return self.parse_prop['mat_name']

    @mat_name.setter
    def mat_name(self, value):
        self._mat_name = value

    @property
    def mat_formula(self):
        return self.parse_prop['mat_formula']

    @mat_formula.setter
    def mat_formula(self, value):
        self._mat_formula = value

    @property
    def atom_elements(self):
        return np.array(self.parse_prop['atom_elements'])

    @atom_elements.setter
    def atom_elements(self, value):
        self._atom_elements = value

    @property
    def atom_numbers(self):
        return self.parse_prop['atom_numbers']

    @atom_numbers.setter
    def atom_numbers(self, value):
        self._atom_numbers = value

    @property
    def atom_xyz(self):
        return np.array(self.parse_prop['xyz_list'])

    @atom_xyz.setter
    def atom_xyz(self, value):
        self._atom_xyz = value

    @property
    def atom_xyz_center(self):
        return np.array(self.parse_prop['xyz_center_list'])

    @atom_xyz_center.setter
    def atom_xyz_center(self, value):
        self._atom_xyz_center = value

    @property
    def atom_bond_block(self):
        return self.parse_prop['bond_block']

    @atom_bond_block.setter
    def atom_bond_block(self, value):
        self._atom_bond_block = value

    @property
    def atom_bond_numbers(self):
        return self.parse_prop['bond_numbers']

    @atom_bond_numbers.setter
    def atom_bond_numbers(self, value):
        self._atom_bond_numbers = value

    # *** observer prop
    @property
    def limits(self):
        return self._limits

    @limits.setter
    def limits(self, value):
        self._limits = []
        self._limits = value

    @property
    def robs(self):
        return self._robs

    @robs.setter
    def robs(self, value):
        self._robs = value

    @property
    def tetaNo(self):
        return self._tetaNo

    @tetaNo.setter
    def tetaNo(self, value):
        self._tetaNo = value

    @property
    def phiNo(self):
        return self._phiNo

    @phiNo.setter
    def phiNo(self, value):
        self._phiNo = value

    @property
    def dataNo(self):
        return self._dataNo

    @dataNo.setter
    def dataNo(self, value):
        self._dataNo = value

    @property
    def obsCoordinate(self):
        return self._obsCoordinate

    @obsCoordinate.setter
    def obsCoordinate(self, value):
        self._obsCoordinate = []
        self._obsCoordinate = value

    def __update_atom_prop(self, prop_name):
        '''
        Update atom prop

        Parameters
        ----------
        prop_name: str
            atom prop name
        '''
        switchProp = {
            'header_block': 1,
            'counts_line': 1,
            'mat_cid': self.__update_mat_cid,
            'mat_name': self.__update_mat_name,
            'mat_formula': self.__update_mat_formula,
            'atom_numbers': self.__update_atom_numbers,
            'atom_elements': self.__update_atom_elements,
            'bond_numbers': self.__update_atom_bond_numbers,
            'atom_block': 1,
            'bond_block': self.__update_atom_bond_block,
            'xyz_list': self.__update_atom_xyz,
            'xyz_center_list': self.__update_atom_xyz_center
        }
        # select prop
        propSelection = switchProp.get(prop_name)
        propSelection(self.parse_prop[prop_name])

    def __update_mat_cid(self, prop_val):
        self.mat_cid = prop_val

    def __update_mat_name(self, prop_val):
        self.mat_name = prop_val

    def __update_mat_formula(self, prop_val):
        self.mat_formula = prop_val

    def __update_atom_numbers(self, prop_val):
        self.atom_numbers = prop_val

    def __update_atom_elements(self, prop_val):
        self.atom_elements = prop_val

    def __update_atom_xyz(self, prop_val):
        self.atom_xyz = prop_val

    def __update_atom_xyz_center(self, prop_val):
        self.atom_xyz_center = prop_val

    def __update_atom_bond_block(self, prop_val):
        self.atom_bond_block = prop_val

    def __update_atom_bond_numbers(self, prop_val):
        self.atom_bond_numbers = prop_val

    def convert_atom_bonds(self, atom_bonds):
        '''
        Convert atom bonds to 1d list
        '''
        atom_bonds_1d = []
        for atom in atom_bonds:
            for bond in atom['bonds']:
                atom_bonds_1d.append({
                    'id1': atom['id'],
                    'symbol1': atom['symbol'],
                    'id2': bond[0],
                    'symbol2': bond[1],
                    'bond_type': bond[3],
                    'bond_symbol': bond[2]
                })
        return atom_bonds_1d

    def distance_matrix(self):
        '''
        Build a matrix of atom-atom distance
        '''
        return Compute.atoms_distance_matrix(self.xyzList, self.atom_elements)

    def distance_atoms(self, atom_symbols, atom_index=[]):
        '''
        Calculate distance between two different atoms

        Parameters
        ----------
        atom_symbols: list
            atom symbol list such as ['C','H']
        atom_index: list
            atom index such as [0,1]

        Returns
        -------
        distance: float
            distance between two atoms
        '''
        return Compute.atoms_distance(self.xyzList, self.atom_elements, atom_symbols, atom_index)

__str__()

Return info about the mat

Source code in molvizr3d/docs/compound.py
def __str__(self):
    '''
    Return info about the mat
    '''
    # check
    if self.parse_prop['mat_name'] is not None:
        return str(self.parse_prop['mat_name'])
    else:
        return str(self.parse_prop['atom_elements'])

__update_atom_prop(prop_name)

Update atom prop

Parameters

prop_name: str atom prop name

Source code in molvizr3d/docs/compound.py
def __update_atom_prop(self, prop_name):
    '''
    Update atom prop

    Parameters
    ----------
    prop_name: str
        atom prop name
    '''
    switchProp = {
        'header_block': 1,
        'counts_line': 1,
        'mat_cid': self.__update_mat_cid,
        'mat_name': self.__update_mat_name,
        'mat_formula': self.__update_mat_formula,
        'atom_numbers': self.__update_atom_numbers,
        'atom_elements': self.__update_atom_elements,
        'bond_numbers': self.__update_atom_bond_numbers,
        'atom_block': 1,
        'bond_block': self.__update_atom_bond_block,
        'xyz_list': self.__update_atom_xyz,
        'xyz_center_list': self.__update_atom_xyz_center
    }
    # select prop
    propSelection = switchProp.get(prop_name)
    propSelection(self.parse_prop[prop_name])

convert_atom_bonds(atom_bonds)

Convert atom bonds to 1d list

Source code in molvizr3d/docs/compound.py
def convert_atom_bonds(self, atom_bonds):
    '''
    Convert atom bonds to 1d list
    '''
    atom_bonds_1d = []
    for atom in atom_bonds:
        for bond in atom['bonds']:
            atom_bonds_1d.append({
                'id1': atom['id'],
                'symbol1': atom['symbol'],
                'id2': bond[0],
                'symbol2': bond[1],
                'bond_type': bond[3],
                'bond_symbol': bond[2]
            })
    return atom_bonds_1d

distance_atoms(atom_symbols, atom_index=[])

Calculate distance between two different atoms

Parameters

atom_symbols: list atom symbol list such as ['C','H'] atom_index: list atom index such as [0,1]

Returns

distance: float distance between two atoms

Source code in molvizr3d/docs/compound.py
def distance_atoms(self, atom_symbols, atom_index=[]):
    '''
    Calculate distance between two different atoms

    Parameters
    ----------
    atom_symbols: list
        atom symbol list such as ['C','H']
    atom_index: list
        atom index such as [0,1]

    Returns
    -------
    distance: float
        distance between two atoms
    '''
    return Compute.atoms_distance(self.xyzList, self.atom_elements, atom_symbols, atom_index)

distance_matrix()

Build a matrix of atom-atom distance

Source code in molvizr3d/docs/compound.py
def distance_matrix(self):
    '''
    Build a matrix of atom-atom distance
    '''
    return Compute.atoms_distance_matrix(self.xyzList, self.atom_elements)

compute

Compute

computational chemistry

Source code in molvizr3d/docs/compute.py
class Compute():
    '''
    computational chemistry
    '''

    def __init__(self):
        pass

    @staticmethod
    def cal_atoms_distance(xyzAtom1, xyzAtom2):
        '''
        calculate distance between two atoms (center to center)
        '''
        return np.linalg.norm(xyzAtom1-xyzAtom2)

    @staticmethod
    def atoms_distance_matrix(xyzList, atomName):
        '''
        build a matrix containing a matrix of distance between two different atoms

        args:
            xyzList: xyz list of atoms
            atomName: atom name list such as ['C','H','H','H','H']
        '''
        # atom no
        atomNo = len(atomName)
        atomLength = np.zeros((atomNo, atomNo))
        for i in range(atomNo):
            # atom1
            atom1XYZ = xyzList[i]
            for j in range(atomNo):
                # atom2
                atom2XYZ = xyzList[j]
                if j != i:
                    _length = Compute.cal_atoms_distance(atom1XYZ, atom2XYZ)
                else:
                    _length = 0
                # save
                atomLength[i, j] = _length

        # res
        return atomLength

    @staticmethod
    def atoms_distance(xyzList, atomName, atom_symbols, atom_index):
        '''
        build a matrix containing a matrix of distance between two different atoms

        args:
            xyzList: xyz list of atoms
            atomName: atom name list such as ['C','H','H','H','H']
        '''
        try:
            # size
            atom_symbols_size = len(atom_symbols)
            atom_index_size = len(atom_index)

            # check
            if atom_symbols_size > 2 or atom_index_size > 2:
                raise Exception(
                    'atom symbol/index list must have two elements.')

            if atom_index_size == 0:
                # find the index of the first element
                atom1Index = np.where(atomName == atom_symbols[0])[0][0]
                atom2Index = np.where(atomName == atom_symbols[1])[0][0]
                # set
                atom1XYZ = xyzList[atom1Index]
                atom2XYZ = xyzList[atom2Index]
                _length = Compute.cal_atoms_distance(atom1XYZ, atom2XYZ)
            elif atom_index_size == 2:
                # set
                atom1XYZ = xyzList[atom_index[0]]
                atom2XYZ = xyzList[atom_index[1]]
                _length = Compute.cal_atoms_distance(atom1XYZ, atom2XYZ)
            elif atom_index_size > 2:
                raise Exception(
                    'atom symbol/index list must have two elements.')

            # res
            return _length
        except Exception as e:
            raise

atoms_distance(xyzList, atomName, atom_symbols, atom_index) staticmethod

build a matrix containing a matrix of distance between two different atoms

Parameters:

Name Type Description Default
xyzList

xyz list of atoms

required
atomName

atom name list such as ['C','H','H','H','H']

required
Source code in molvizr3d/docs/compute.py
@staticmethod
def atoms_distance(xyzList, atomName, atom_symbols, atom_index):
    '''
    build a matrix containing a matrix of distance between two different atoms

    args:
        xyzList: xyz list of atoms
        atomName: atom name list such as ['C','H','H','H','H']
    '''
    try:
        # size
        atom_symbols_size = len(atom_symbols)
        atom_index_size = len(atom_index)

        # check
        if atom_symbols_size > 2 or atom_index_size > 2:
            raise Exception(
                'atom symbol/index list must have two elements.')

        if atom_index_size == 0:
            # find the index of the first element
            atom1Index = np.where(atomName == atom_symbols[0])[0][0]
            atom2Index = np.where(atomName == atom_symbols[1])[0][0]
            # set
            atom1XYZ = xyzList[atom1Index]
            atom2XYZ = xyzList[atom2Index]
            _length = Compute.cal_atoms_distance(atom1XYZ, atom2XYZ)
        elif atom_index_size == 2:
            # set
            atom1XYZ = xyzList[atom_index[0]]
            atom2XYZ = xyzList[atom_index[1]]
            _length = Compute.cal_atoms_distance(atom1XYZ, atom2XYZ)
        elif atom_index_size > 2:
            raise Exception(
                'atom symbol/index list must have two elements.')

        # res
        return _length
    except Exception as e:
        raise

atoms_distance_matrix(xyzList, atomName) staticmethod

build a matrix containing a matrix of distance between two different atoms

Parameters:

Name Type Description Default
xyzList

xyz list of atoms

required
atomName

atom name list such as ['C','H','H','H','H']

required
Source code in molvizr3d/docs/compute.py
@staticmethod
def atoms_distance_matrix(xyzList, atomName):
    '''
    build a matrix containing a matrix of distance between two different atoms

    args:
        xyzList: xyz list of atoms
        atomName: atom name list such as ['C','H','H','H','H']
    '''
    # atom no
    atomNo = len(atomName)
    atomLength = np.zeros((atomNo, atomNo))
    for i in range(atomNo):
        # atom1
        atom1XYZ = xyzList[i]
        for j in range(atomNo):
            # atom2
            atom2XYZ = xyzList[j]
            if j != i:
                _length = Compute.cal_atoms_distance(atom1XYZ, atom2XYZ)
            else:
                _length = 0
            # save
            atomLength[i, j] = _length

    # res
    return atomLength

cal_atoms_distance(xyzAtom1, xyzAtom2) staticmethod

calculate distance between two atoms (center to center)

Source code in molvizr3d/docs/compute.py
@staticmethod
def cal_atoms_distance(xyzAtom1, xyzAtom2):
    '''
    calculate distance between two atoms (center to center)
    '''
    return np.linalg.norm(xyzAtom1-xyzAtom2)

CalculateMolecularMass(atom_elements, element_source)

calculate molecular mass [g/mol]

Parameters:

Name Type Description Default
atom_elements

such as C, H

required
element_source

periodic element table

required
Source code in molvizr3d/docs/compute.py
def CalculateMolecularMass(atom_elements, element_source):
    '''
    calculate molecular mass [g/mol]

    args:
        atom_elements: such as C, H
        element_source: periodic element table
    '''
    try:
        # # check
        # if element_source is None:
        #     # load periodic table of elements
        #     element_source = elements()
        # res
        res = 0
        # atom element size
        atomElementsSize = len(atom_elements)
        # atom property
        _atom_property = ['AtomicMass']
        # loop
        for i in range(atomElementsSize):
            _atom_symbol = atom_elements[i]
            _atom_prop_res = element_source.atom_properties(
                _atom_symbol, _atom_property)
            _atom_prop_val = _atom_prop_res.get(_atom_property[0])
            res += float(_atom_prop_val)

        return res
    except Exception as e:
        raise

element

Element

pub chem elements (periodic table of the elements)

Source code in molvizr3d/docs/element.py
class Element():
    '''
    pub chem elements (periodic table of the elements)
    '''

    _elementsource = ''
    _ele = ''

    def __init__(self, atom_symbol=''):
        self.elementsource = self.__load_elements()
        self._ele = atom_symbol

    def __call__(self, ):
        print(
            'element object such as Carbon (C), get properties by calling atom_properties()')

    @property
    def elementsource(self):
        return self._elementsource

    @elementsource.setter
    def elementsource(self, value):
        self._elementsource = value

    @property
    def ele(self):
        return self._ele

    @ele.setter
    def ele(self, value):
        pass

    def __load_elements(self):
        '''
        load elements from a csv file
        '''
        try:
            # data file
            dataFile = 'PubChemElements_all.csv'
            # abs path
            pathAbs = os.path.abspath(os.path.dirname(__file__))
            # relative path to database file
            dataPathDirRel = '../data'
            # database file
            dataPath = os.path.join(pathAbs, dataPathDirRel, dataFile)

            with open(dataPath, 'rb') as f:
                df = pd.read_csv(f)

            return df

        except Exception as e:
            raise Exception(e)

    def properties(self):
        '''
        return all atom properties
        '''
        df = self.elementsource
        filt = df['Symbol'] == str(self._ele).strip()
        return df.loc[filt]

    def find_atom(self, atom_symbol):
        '''
        return the selected atom properties
        '''
        df = self.elementsource
        filt = df['Symbol'] == str(atom_symbol).strip()
        return df.loc[filt]

    def atom_properties(self, atom_symbol, atom_properties=[]):
        '''
        find desired atom properties

        args:
            atom_symbol: atom symbol
            atom_properties: a list of desired properties

        return:
            a dict of property
        '''
        try:
            # property size
            atomPropertySize = len(atom_properties)
            # res
            resDict = {}

            # check
            if atomPropertySize == 0:
                raise Exception('property list is empty.')

            df = self.elementsource
            filt = df['Symbol'] == str(atom_symbol).strip()

            # check
            if atomPropertySize == 1:
                rowRes = df.loc[filt][atom_properties[0]]
                rowRes = rowRes.to_numpy()[0]
                # add prop
                resDict[str(atom_properties[0])] = rowRes
            elif atomPropertySize > 1:
                rowRes = df.loc[filt][atom_properties]
                rowRes = rowRes.to_numpy()[0]
                # add prop
                for i in range(atomPropertySize):
                    resDict[str(atom_properties[i])] = rowRes[i]
            # res
            return resDict

        except Exception as e:
            raise Exception(e)

    def find_atom_by_property(self, atom_property_name, atom_property_value=[]):
        '''
        find desired atom properties

        args:
            atom_property_name: atom property such as atomic number
            atom_property_value: carbon = 6

        return:
            string
        '''
        try:
            # size
            atom_property_value_size = len(atom_property_value)
            atom_property_name_size = len(str(atom_property_name))

            # res
            res = []

            # check
            if atom_property_name_size == 0 or atom_property_value_size == 0:
                raise Exception('args error.')

            df = self.elementsource

            if atom_property_value_size == 1:
                filt = df[str(atom_property_name)] == atom_property_value[0]
                _rowRes = df.loc[filt][['Symbol']]
                _rowRes = _rowRes.to_numpy()[0]
                # check
                if len(_rowRes) > 0:
                    # add prop
                    _val = {'symbol': _rowRes[0], str(
                        atom_property_name): atom_property_value[0]}
                    res.append(_val)
                else:
                    raise Exception('element not found.')
            elif atom_property_value_size > 1:
                for i in range(atom_property_value_size):
                    filt = df[str(atom_property_name)
                              ] == atom_property_value[i]
                    _rowRes = df.loc[filt][['Symbol']]
                    _rowRes = _rowRes.to_numpy()[0]
                    # add
                    _val = {'symbol': _rowRes[0], str(
                        atom_property_name): atom_property_value[i]}
                    # save
                    res.append(_val)

            # res
            return res

        except Exception as e:
            raise Exception(e)

__load_elements()

load elements from a csv file

Source code in molvizr3d/docs/element.py
def __load_elements(self):
    '''
    load elements from a csv file
    '''
    try:
        # data file
        dataFile = 'PubChemElements_all.csv'
        # abs path
        pathAbs = os.path.abspath(os.path.dirname(__file__))
        # relative path to database file
        dataPathDirRel = '../data'
        # database file
        dataPath = os.path.join(pathAbs, dataPathDirRel, dataFile)

        with open(dataPath, 'rb') as f:
            df = pd.read_csv(f)

        return df

    except Exception as e:
        raise Exception(e)

atom_properties(atom_symbol, atom_properties=[])

find desired atom properties

Parameters:

Name Type Description Default
atom_symbol

atom symbol

required
atom_properties

a list of desired properties

[]
return

a dict of property

Source code in molvizr3d/docs/element.py
def atom_properties(self, atom_symbol, atom_properties=[]):
    '''
    find desired atom properties

    args:
        atom_symbol: atom symbol
        atom_properties: a list of desired properties

    return:
        a dict of property
    '''
    try:
        # property size
        atomPropertySize = len(atom_properties)
        # res
        resDict = {}

        # check
        if atomPropertySize == 0:
            raise Exception('property list is empty.')

        df = self.elementsource
        filt = df['Symbol'] == str(atom_symbol).strip()

        # check
        if atomPropertySize == 1:
            rowRes = df.loc[filt][atom_properties[0]]
            rowRes = rowRes.to_numpy()[0]
            # add prop
            resDict[str(atom_properties[0])] = rowRes
        elif atomPropertySize > 1:
            rowRes = df.loc[filt][atom_properties]
            rowRes = rowRes.to_numpy()[0]
            # add prop
            for i in range(atomPropertySize):
                resDict[str(atom_properties[i])] = rowRes[i]
        # res
        return resDict

    except Exception as e:
        raise Exception(e)

find_atom(atom_symbol)

return the selected atom properties

Source code in molvizr3d/docs/element.py
def find_atom(self, atom_symbol):
    '''
    return the selected atom properties
    '''
    df = self.elementsource
    filt = df['Symbol'] == str(atom_symbol).strip()
    return df.loc[filt]

find_atom_by_property(atom_property_name, atom_property_value=[])

find desired atom properties

Parameters:

Name Type Description Default
atom_property_name

atom property such as atomic number

required
atom_property_value

carbon = 6

[]
return

string

Source code in molvizr3d/docs/element.py
def find_atom_by_property(self, atom_property_name, atom_property_value=[]):
    '''
    find desired atom properties

    args:
        atom_property_name: atom property such as atomic number
        atom_property_value: carbon = 6

    return:
        string
    '''
    try:
        # size
        atom_property_value_size = len(atom_property_value)
        atom_property_name_size = len(str(atom_property_name))

        # res
        res = []

        # check
        if atom_property_name_size == 0 or atom_property_value_size == 0:
            raise Exception('args error.')

        df = self.elementsource

        if atom_property_value_size == 1:
            filt = df[str(atom_property_name)] == atom_property_value[0]
            _rowRes = df.loc[filt][['Symbol']]
            _rowRes = _rowRes.to_numpy()[0]
            # check
            if len(_rowRes) > 0:
                # add prop
                _val = {'symbol': _rowRes[0], str(
                    atom_property_name): atom_property_value[0]}
                res.append(_val)
            else:
                raise Exception('element not found.')
        elif atom_property_value_size > 1:
            for i in range(atom_property_value_size):
                filt = df[str(atom_property_name)
                          ] == atom_property_value[i]
                _rowRes = df.loc[filt][['Symbol']]
                _rowRes = _rowRes.to_numpy()[0]
                # add
                _val = {'symbol': _rowRes[0], str(
                    atom_property_name): atom_property_value[i]}
                # save
                res.append(_val)

        # res
        return res

    except Exception as e:
        raise Exception(e)

properties()

return all atom properties

Source code in molvizr3d/docs/element.py
def properties(self):
    '''
    return all atom properties
    '''
    df = self.elementsource
    filt = df['Symbol'] == str(self._ele).strip()
    return df.loc[filt]

molparser

MolParser

Parse different formats of molecule files such as sdf, json, ...

Source code in molvizr3d/docs/molparser.py
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
class MolParser():
    '''
    Parse different formats of molecule files such as sdf, json, ...
    '''
    _mat = {}

    def __init__(self, filepath):
        self.filepath = filepath

    @property
    def mat(self):
        return self._mat

    @mat.setter
    def mat(self, value):
        self._mat = copy.deepcopy(value)

    def read_file(self, sourceContent={}):
        '''
        Read structure file 
            1. from file
            2. download from api

        Parameters
        ----------
        filepath : str
            full file name with directory 

        Returns
        -------
        res : dict
            mol: mol object
            structure: structure object

        hints:
            mol: mol object
                header_block: header block
                counts_line: counts line
                atom_numbers: atom number
                mat_cid: cid number
                mat_name: IUPAC name
                mat_formula: formula
                mat_mass: molecular mass
                atom_names: atom list
                atom_xyz: atom coordinate
                bond_numbers: bond number
                bond_list: bond list
                bond_matrix: bond matrix
                bond_xyz: bond coordinate

            structure: structure object
                mol: mol object
                mat: mat object
        '''
        try:
            # get file path
            filePath = self.filepath

            # check
            if filePath:
                # open file and get content
                fileContent, fileDir, fileName, fileFormat = Utility.OpenFile(
                    filePath)
            else:
                # read string/json and ... files
                fileContent, fileFormat = Utility.ReadContent(
                    sourceContent)

            # method selection
            parserFun = {
                'sdf': self.sdf_parser,
                'json': self.json_parser
            }

            # parse file
            parserSelection = parserFun.get(fileFormat)
            parserRes = parserSelection(fileContent)
            return parserRes

        except Exception as e:
            raise Exception(e)

    def sdf_parser(self, sdfSource, sdfVersion='V2000'):
        '''
        Parse sdf file

        Parameters
        ----------
        sdfSource : str
            sdf file content

        sdfVersion : str
            sdf file version (default V2000)

        Returns
        -------
        res : dict
            mol: mol object
                header_block: header block
                counts_line: counts line
                atom_numbers: atom number
                mat_cid: cid number
                mat_name: IUPAC name
                mat_formula: formula
                mat_mass: molecular mass
                atom_names: atom list
                atom_elements: atom list
                bond_numbers: bond number
                atom_block: atoms
                bond_block: bond list
                xyz_list: xyz list
                xyz_center_list: xyz center list
                compound_properties: compound properties

        '''
        # decode binary
        # if binary file
        # sdfSource = sdfSource.decode('utf-8')
        # if text file
        sdfSource = sdfSource
        # create list
        sdfSourceList = sdfSource.splitlines()

        # header block
        headerBlock = sdfSourceList[0:3]

        # counts line
        countsLine = sdfSourceList[3]
        if countsLine.find('V2000') == -1:
            raise Exception(
                'SDF file version is not compatible with this method, import 2000 version.')
        # check
        countsLineList = countsLine.split()

        # find 'M END'
        MENDi = -1
        MENDi = sdfSourceList.index('M  END')
        # connection table
        if MENDi != -1:
            connectionTable = sdfSourceList[4:MENDi]

        # *** check
        _countsLineListSize = len(countsLineList)
        if _countsLineListSize == 10:
            # atom no
            atomNo = int(countsLineList[0])
            # bond no
            bondNo = int(countsLineList[1])
        elif _countsLineListSize == 9:
            _connectionTableLines = connectionTable
            _connectionTableLinesSize = len(_connectionTableLines)
            # first record
            _firstRecord = _connectionTableLines[0]
            _firstRecordSize = len(_firstRecord)
            _secondRecord = _connectionTableLines[0]
            _secondRecordSize = len(_secondRecord)
            if _firstRecordSize != _secondRecordSize:
                raise Exception('sdf file is not coded correctly.')
            # loop
            for l in range(_connectionTableLinesSize):
                _loopRecordSize = len(_connectionTableLines[l])
                if _loopRecordSize < _firstRecordSize:
                    # atom no
                    atomNo = int(l)
                    # bond no
                    bondNo = int(str(countsLineList[0]).split(str(atomNo))[1])
                    # break
                    break
        else:
            raise Exception('3rd line of the sdf file is not coded correctly.')

        # element rows
        elementRows = connectionTable[0:atomNo]
        # bond rows
        bondRows = connectionTable[atomNo:]

        # other vars
        compoundPropertiesList = MolParser.__var_finder(sdfSource)
        # dict vars
        compoundProperties = MolParser.__var_analyzer(compoundPropertiesList)
        # extract:
        PUBCHEM_COMPOUND_CID = compoundProperties.get('PUBCHEM_COMPOUND_CID')
        PUBCHEM_IUPAC_NAME = compoundProperties.get('PUBCHEM_IUPAC_NAME')
        PUBCHEM_EXACT_MASS = compoundProperties.get('PUBCHEM_EXACT_MASS')
        PUBCHEM_MOLECULAR_FORMULA = compoundProperties.get(
            'PUBCHEM_MOLECULAR_FORMULA')
        PUBCHEM_MOLECULAR_WEIGHT = compoundProperties.get(
            'PUBCHEM_MOLECULAR_WEIGHT')

        atoms = []
        atomList = []
        xyzList = []

        # atoms position
        for i in range(atomNo):
            _atomRow = elementRows[i].split()
            # position
            _x = float(_atomRow[0])
            _y = float(_atomRow[1])
            _z = float(_atomRow[2])
            # name
            _name = _atomRow[3]

            # atom list
            atomList.append(_name)

            # atom info
            atom = {
                'id': i+1,
                'symbol': _name,
                'index': i+1,
                'x': _x,
                'y': _y,
                'z': _z,
                'position': {
                    'x': _x,
                    'y': _y,
                    'z': _z
                },
                'xyz': [_x, _y, _z]
            }
            # save atom info
            atoms.append(atom)
            # xyz
            xyzList.append([_x, _y, _z])

        # set
        xyzList = np.array(xyzList)

        # object base
        objectBaseCoordinate = Structure.CenterPoints(xyzList)
        # print(f"objectBaseCoordinate: {objectBaseCoordinate}")

        # move to the center [0,0,0]
        xyzCenterList, movingCoordinate = Structure.CenterObject(
            xyzList, objectBaseCoordinate)
        # print(f"xyzCenterList: {xyzCenterList} \n movingCoordinate: \n {movingCoordinate}")

        # create mat formula
        matFormula = Structure.create_formula(atomList)
        # calculate molecular mass
        # matMass = 1

        # bond analysis
        bondList = []
        atomBonds = []

        # atomNo: *** atom id in the structure ***
        for i in range(atomNo):
            # name
            _nameAtom1 = str(atomList[i])
            # index [not duplicated element]
            # _nameAtom1Index = atomList.index(_nameAtom1)
            _nameAtom1Index = i+1
            # check bond type
            for j in range(bondNo):
                _bondRow = bondRows[j].split()
                # starts from 1 to ... (not 0)
                _nameAtomBondRow = int(_bondRow[0])
                # check bond exist
                if _nameAtom1Index == _nameAtomBondRow:
                    # atom 2 index
                    _indexAtom = int(_bondRow[1])
                    # atom 2 name
                    _nameAtom2 = str(atomList[_indexAtom-1])
                    # bound type
                    _bondType = int(_bondRow[2])
                    # str bond
                    _bondName = _nameAtom1 + _nameAtom2
                    # atom bond
                    atomBonds.append(
                        (_indexAtom, _nameAtom2, _bondName, _bondType))

            if len(atomBonds) > 0:
                # save
                _bondList = {
                    'id': _nameAtom1Index,
                    'symbol': _nameAtom1,
                    'bonds': atomBonds
                }
                bondList.append(_bondList)

            # reset
            atomBonds = []
            _bondList = {}

        # res
        res = {
            'header_block': headerBlock,
            'counts_line': countsLine,
            'atom_numbers': atomNo,
            'mat_cid': PUBCHEM_COMPOUND_CID,
            'mat_name': PUBCHEM_IUPAC_NAME if PUBCHEM_IUPAC_NAME is not None else '',
            'mat_formula': PUBCHEM_MOLECULAR_FORMULA if PUBCHEM_MOLECULAR_FORMULA is not None else matFormula,
            'mat_mass': PUBCHEM_EXACT_MASS if PUBCHEM_EXACT_MASS is not None else PUBCHEM_MOLECULAR_WEIGHT,
            'atom_names': atomList,
            'atom_elements': atomList,
            'bond_numbers': bondNo,
            'atom_block': atoms,
            'bond_block': bondList,
            'xyz_list': xyzList,
            'xyz_center_list': xyzCenterList,
            'compound_properties': compoundProperties
        }

        # return
        return res

    def json_parser(self, jsonSource, id_sort=True):
        '''
        parse json file

        Parameters
        ----------
        jsonSource: dict file
            json file content
        id_sort: bool
            if True, sort id

        Returns
        -------
        res: dict
        '''
        try:
            dictSource = jsonSource['PC_Compounds'][0]

            # analyze json file
            # *** id node
            if 'id' in dictSource:
                _idNode = dictSource['id']
                cid = self.__json_parser_id(_idNode)

            # *** atoms
            if 'atoms' in dictSource:
                _atomsNode = dictSource['atoms']
                # atom ids, element atomic number
                atomIds, _elementAtomicNumber = self.__json_parser_atoms(
                    _atomsNode)

            # atom numbers
            atomNo = len(atomIds)

            # atom list (element list)
            elementListRes, elementList = self.__find_element_symbol(
                _elementAtomicNumber)

            # *** bonds
            if 'bonds' in dictSource:
                _bonds = dictSource['bonds']
                # atom1 id, atom2 id, bond types
                atomId1, atomId2, bondTypes, bondMatrix = self.__json_parser_bonds(
                    _bonds)

            # bond numbers
            bondNo = len(atomId1)

            # *** coords
            if 'coords' in dictSource:
                _coords = dictSource['coords']  # list
                # coords type, aid, xyzList
                coords_type, coords_aid, xyzList, structure_type = self.__json_parser_coords(
                    _coords)

            # *** charge
            if 'charge' in dictSource:
                _charge = dictSource['charge']  # scaler
                charge = self.__json_parser_charge(_charge)

            # *** props
            if 'props' in dictSource:
                _props = dictSource['props']  # list of dict
                propDict = self.__json_parser_props(_props)

            # *** count
            if 'count' in dictSource:
                _count = dictSource['count']  # dict
                countList = self.__json_parser_count(_count)

            # interpret
            __json_atom_position_res = self.__json_atom_position(
                atomNo, elementList, xyzList)

            # bond block
            __json_atom_bondblock_res = self.__json_atom_bondblock(
                atomNo, bondNo, elementList, bondMatrix)

            # bondBlock: used for Matview class
            # atomDetails, bondBlock, xyzCenterList = self.__json_atom_analyzer(
            #     atomNo, bondNo, elementList, xyzList, bondMatrix)

            # *** origin info
            origin_info = {
                'atom_elements': __json_atom_position_res.get('elementList'),
                'atom_atomic_number': _elementAtomicNumber,
                'atom_details': __json_atom_position_res.get('atomDetails'),
                'bond_block': __json_atom_bondblock_res.get('bondBlock'),
                'bond_list': __json_atom_bondblock_res.get('bondMatrix'),
                'xyz_list': __json_atom_position_res.get('xyzList'),
                'xyz_center_list': __json_atom_position_res.get('xyzCenterList'),
            }

            # *** define new ids for mat and update
            # *** xyzList, bondMatrix, elementlist, elementAtomicNumber
            # *** bond_list = bondMatrix
            # *** atom_block = atom_details
            # if id_sort:
            mat_position_info, atom_id_conversion, xyz_list_sorted, \
                element_list_sorted, bond_list_sorted = self.SetAtomId(
                    xyzList, elementList, bondMatrix)

            # interpret
            __json_atom_position_res2 = self.__json_atom_position(
                atomNo, element_list_sorted, xyz_list_sorted)
            # set
            atom_block_sorted = __json_atom_position_res2.get('atomDetails')
            xyz_list_sorted = __json_atom_position_res2.get('xyzList')
            xyz_center_list_sorted = __json_atom_position_res2.get(
                'xyzCenterList')

            # bond block
            __json_atom_bondblock_res2 = self.__json_atom_bondblock(
                atomNo, bondNo, element_list_sorted, bond_list_sorted)
            # set
            bond_block_sorted = __json_atom_bondblock_res2.get('bondBlock')

            # atomic number sorted
            element_atomic_number = self.arrange_prop(
                _elementAtomicNumber, atom_id_conversion[:, 0])

            # update properties
            # name
            mat_name = propDict.get('IUPAC Name')
            if mat_name is None:
                mat_name = 'NULL'

            # formula
            mat_formula = propDict.get('Molecular Formula')
            if mat_formula is None:
                # create mat formula
                mat_formula = 'NULL'

            # molecular weight
            mat_mass = propDict.get('Molecular Weight')
            if mat_mass is None:
                # mat molecular weight/mass
                mat_mass = 0
            else:
                mat_mass = float(mat_mass)

            # res
            res = {
                'header_block': '',
                'counts_line': '',
                'mat_structure': structure_type,
                'mat_cid': cid,
                'mat_name': mat_name,
                'mat_formula': mat_formula,
                'mat_mass': mat_mass,
                'atom_numbers': atomNo,
                'atom_elements': element_list_sorted,
                'atom_atomic_number': element_atomic_number,
                'atom_block': atom_block_sorted,
                'bond_numbers': bondNo,
                'bond_block': bond_block_sorted,
                'bond_list': bond_list_sorted,
                'xyz_list': xyz_list_sorted,
                'xyz_center_list': xyz_center_list_sorted,
                'compound_properties': propDict,
                'mat_info_origin': origin_info
            }

            return res

        except Exception as e:
            raise Exception(e)

    def __json_parser_id(self, data):
        '''
        Return cid 

        Parameters
        ----------
        data : dict
            json data

        Returns
        -------
        node : int
            cid
        '''
        # *** id node
        node = data['id']['cid']
        return node

    def __json_parser_atoms(self, data):
        '''
        Return atom id, atom atomic number

        Parameters
        ----------
        data : dict
            json data

        Returns
        -------
        _aid : int
            atom id
        _elementAtomicNumber : int
            atom atomic number
        '''
        # aid (atom id)
        _aid = data['aid']
        # element (atomic number)
        _elementAtomicNumber = data['element']
        return _aid, _elementAtomicNumber

    def __json_parser_bonds(self, data):
        '''
        Return atom1 id, atom2 is, bond type

        Parameters
        ----------
        data : dict
            json data

        Returns
        -------
        _aid1 : int
            atom1 id
        _aid2 : int
            atom2 id
        _order : int
            bond type
        '''
        # aid1 (atom id)
        _aid1 = data['aid1']
        # aid2 (atom id)
        _aid2 = data['aid2']
        # order
        _order = data['order']

        # transform
        bondMatrix = np.array([_aid1, _aid2, _order])
        bondMatrix = np.transpose(bondMatrix)

        return _aid1, _aid2, _order, bondMatrix

    def __json_parser_coords(self, data):
        '''
        Return coordination type, coordination id, xyzList

        Parameters
        ----------
        data : dict
            json data

        Returns
        -------
        _coords_type : str
            coordination type
        _coords_aid : int
            coordination id
        xyzList : np.array
            xyzList
        structureType : str
            2d or 3d
        '''
        data = data[0]
        _coords_type = data['type']  # list
        _coords_aid = data['aid']  # list
        _coords_conformers = data['conformers'][0]
        _x = _coords_conformers.get('x')
        # atomNo
        atomNo = len(_x)
        _y = _coords_conformers.get('y')

        _z = _coords_conformers.get('z') if _coords_conformers.get(
            'z') is not None else np.zeros(atomNo)
        # transform
        xyzList = np.array([_x, _y, _z])
        xyzList = np.transpose(xyzList)

        # 2d/3d structure
        structureType = "2d" if np.count_nonzero(_z) == 0 else '3d'

        return _coords_type, _coords_aid, xyzList, structureType

    def __json_parser_charge(self, data):
        '''
        Get charge

        Parameters
        ----------
        data : dict
            json data

        Returns
        -------
        node : int
            charge
        '''
        # *** id node
        node = data
        return node

    def __json_parser_props(self, data):
        '''
        Return a list of all properties

        Parameters
        ----------
        data : dict
            json data

        Returns
        -------
        res : dict
            a list of all properties
        '''
        res = {}
        for i in range(len(data)):
            _keySet = data[i]['urn']['label']
            _valueSet = list(data[i]['value'].values())
            res[str(_keySet)] = _valueSet[0]

        return res

    def __json_parser_count(self, data):
        '''
        Return a list of all count

        Parameters
        ----------
        data : dict
            json data

        Returns
        -------
        res : dict
            a list of all count
        '''
        res = {}
        for key, value in data.items():
            res[key] = value
        return res

    def __json_atom_analyzer(self, atomNo, bondNo, elementList, xyzList, bondMatrix):
        '''
        Define xyz list and bond list

        Parameters
        ----------
        atomNo : int
            atom number
        bondNo : int
            bond number
        elementList : list
            element list
        xyzList : np.array
            xyz list
        bondMatrix : np.array
            bond matrix

        Returns
        -------
        atomDetails : list
            atom details
        objectBaseCoordinate : list
            object base coordinate
        bondDetails : list
            bond details
        '''
        # vars
        # *** detail about atoms
        atomDetails = []

        # element symbols
        atomList = elementList

        # atoms position
        for i in range(atomNo):
            _atomRow = xyzList[i, :]
            # position
            _x = float(_atomRow[0])
            _y = float(_atomRow[1])
            _z = float(_atomRow[2])
            # name
            _name = atomList[i]

            # atom info
            atom = {
                'id': i,
                'symbol': _name,
                'index': i,
                'x': _x,
                'y': _y,
                'z': _z,
                'position': {
                    'x': _x,
                    'y': _y,
                    'z': _z
                },
                'xyz': [_x, _y, _z]
            }
            # save atom info
            atomDetails.append(atom)

        # object base
        objectBaseCoordinate = Structure.CenterPoints(xyzList)
        # print(f"objectBaseCoordinate: {objectBaseCoordinate}")

        # move to the center [0,0,0]
        xyzCenterList, movingCoordinate = Structure.CenterObject(
            xyzList, objectBaseCoordinate)
        # print(f"xyzCenterList: {xyzCenterList} \n movingCoordinate: \n {movingCoordinate}")

        # bond analysis
        bondBlock = []
        atomBonds = []

        # atomNo: *** atom id in the structure ***
        for i in range(atomNo):
            # name
            _nameAtom1 = str(atomList[i])
            # index [not duplicated element]
            # _nameAtom1Index = atomList.index(_nameAtom1)
            _nameAtom1Index = i+1
            # check bond type
            for j in range(bondNo):
                _bondRow = bondMatrix[j, :]
                _nameAtomBondRow = int(_bondRow[0])
                # check bond exist
                if _nameAtom1Index == _nameAtomBondRow:
                    # atom 2 index
                    _indexAtom2 = int(_bondRow[1])
                    # atom 2 name
                    _nameAtom2 = str(atomList[_indexAtom2-1])
                    # bound type
                    _bondType = int(_bondRow[2])
                    # str bond
                    _bondName = _nameAtom1 + '-' + _nameAtom2
                    # str id bond
                    _bondId = str(_nameAtom1Index) + '-' + str(_indexAtom2)
                    # atom bond
                    atomBonds.append(
                        (_indexAtom2, _nameAtom2, _bondName, _bondType, _bondId))

            if len(atomBonds) > 0:
                # save
                _bondList = {
                    'id': _nameAtom1Index,
                    'symbol': _nameAtom1,
                    'bonds': atomBonds
                }
                bondBlock.append(_bondList)

            # reset
            atomBonds = []
            _bondList = {}

        # result
        return atomDetails, bondBlock, xyzCenterList

    def __json_atom_position(self, atomNo, elementList, xyzList):
        '''
        Set mat position into the center of cartesian coordination

        Parameters
        ----------
        atomNo : int
            atom number
        elementList : list
            element list
        xyzList : np.array
            xyz list

        Returns
        -------
        res : dict
            a list of all count
        '''
        try:
            # vars
            # *** detail about atoms
            atomDetails = []

            # element symbols
            atomList = elementList

            # atoms position
            for i in range(atomNo):
                _atomRow = xyzList[i, :]
                # position
                _x = float(_atomRow[0])
                _y = float(_atomRow[1])
                _z = float(_atomRow[2])
                # name
                _name = atomList[i]

                # atom info
                atom = {
                    'id': i,
                    'symbol': _name,
                    'index': i,
                    'x': _x,
                    'y': _y,
                    'z': _z,
                    'position': {
                        'x': _x,
                        'y': _y,
                        'z': _z
                    },
                    'xyz': [_x, _y, _z]
                }
                # save atom info
                atomDetails.append(atom)

            # object base
            objectBaseCoordinate = Structure.CenterPoints(xyzList)

            # move to the center [0,0,0]
            xyzCenterList, movingCoordinate = Structure.CenterObject(
                xyzList, objectBaseCoordinate)

            # res
            res = {
                'atomDetails': atomDetails,
                'elementList': elementList,
                'xyzList': xyzList,
                'xyzCenterList': xyzCenterList,
                'movingCoordinate': movingCoordinate
            }

            # res
            return res
        except Exception as e:
            raise Exception(e)

    def __json_atom_bondblock(self, atomNo, bondNo, elementList, bondMatrix):
        '''
        Build bond block which is used by mat view to display mat structure

        Parameters
        ----------
        atomNo : int
            atom number
        bondNo : int
            bond number
        elementList : list
            element list
        bondMatrix : np.array
            bond matrix

        Returns
        -------
        res : dict
            a list of all count
        '''
        try:
            # element symbols
            atomList = elementList

            # bond analysis
            bondBlock = []
            atomBonds = []

            # atomNo: *** atom id in the structure ***
            for i in range(atomNo):
                # name
                _nameAtom1 = str(atomList[i])
                # index [not duplicated element]
                _nameAtom1Index = int(i+1)
                # check bond type
                for j in range(bondNo):
                    # name
                    _bondRow = bondMatrix[j, :]
                    # atom id
                    _nameAtomBondRow = int(_bondRow[0])
                    # check bond exist
                    if _nameAtom1Index == _nameAtomBondRow:
                        # atom 2 index
                        _indexAtom2 = int(_bondRow[1])
                        # atom 2 name
                        _nameAtom2 = str(atomList[_indexAtom2-1])
                        # bound type
                        _bondType = int(_bondRow[2])
                        # str bond
                        _bondName = _nameAtom1 + '-' + _nameAtom2
                        # str id bond
                        _bondId = str(_nameAtom1Index) + '-' + str(_indexAtom2)
                        # atom bond
                        atomBonds.append(
                            (_indexAtom2, _nameAtom2, _bondName, _bondType, _bondId))

                if len(atomBonds) > 0:
                    # save
                    _bondList = {
                        'id': _nameAtom1Index,
                        'symbol': _nameAtom1,
                        'bonds': atomBonds
                    }
                    bondBlock.append(_bondList)

                # reset
                atomBonds = []
                _bondList = {}

            # res
            res = {
                'elementList': elementList,
                'bondMatrix': bondMatrix,
                'bondBlock': bondBlock
            }

            # res
            return res
        except Exception as e:
            Exception(e)

    def __find_element_symbol(self, atomic_numbers):
        '''
        Return element symbols

        Parameters
        ----------
        atomic_numbers : list
            atomic numbers

        Returns
        -------
        res : dict
            a list of all count
        atomList : list
            atom list
        '''
        el = Element()
        # loop
        res = el.find_atom_by_property('AtomicNumber', atomic_numbers)

        # interpret
        atomList = [item['symbol'] for item in res]

        # res
        return res, atomList

    def __var_finder(data):
        '''
        Find variables in a sdf file (single)

        Parameters
        ----------
        data : str
            sdf data

        Returns
        -------
        res : dict
            a list of all count
        '''
        res = re.findall(
            r"(\>\s*\<(.*)\s*\>\s*((.*\n)([^\<\>\$\$\$\$])*))", data, re.M)
        return res

    def __var_analyzer(data):
        '''
        Make a dict of all properties

        Parameters
        ----------
        data : str
            sdf data

        Returns
        -------
        res : dict
            a list of all count
        '''
        res = {}
        dataSize = len(data)
        for i in range(dataSize):
            # name
            varName = data[i][1]
            # val
            varVal = (data[i][2]).split('\n')
            varVal = [item.strip() for item in varVal]
            varVal = list(filter(None, varVal))

            # check
            if len(varVal) == 1:
                _varVal = str(varVal[0])
            else:
                _varVal = varVal
            # set
            _keySet = str(varName)
            _valueSet = _varVal
            # res
            res[_keySet] = _valueSet
            # reset

        return res

    def SetAtomId(self, xyzList, elementList, bondList):
        '''
        Set atom id with respect to their position in a 3d frame

        Parameters
        ----------
        xyzList : list
            list of element (atom) position
        elementList : list
            list of elements
        bondList : list
            list of bond ids and types

        Returns
        -------
        matPosition: list
            list of new ids
        xyzListSorted : list
            list of element (atom) position
        elementListSorted : list
            list of elements
        bondListSorted : list
            list of bond ids and types
        '''
        try:
            # robs position
            robs = OBS_POSITIONS
            # res
            disRes = []
            # calculate distance
            for i in range(len(xyzList)):
                _dis = np.linalg.norm(
                    np.array(robs) - np.array(xyzList[i]))
                _idOld = int(i+1)
                _symbol = elementList[i]
                disRes.append([_idOld, _dis, _symbol])

            # sort
            sortRes = sorted(disRes, key=lambda l: l[1], reverse=True)

            # reverse [old id, distance, symbol]
            sortRes.reverse()

            # save new id [old id, new id, distance, symbol]
            for j in range(len(sortRes)):
                _idNew = int(j+1)
                sortRes[j].insert(1, _idNew)

            # sorted id (old id, new id)
            idConversion = []
            for j in range(len(sortRes)):
                idConversion.append([sortRes[j][0], sortRes[j][1]])

            # build xyzList and elementlist with respect to the new ids
            xyzListSorted = []
            elementListSorted = []
            matPosition = {}
            for j in range(len(sortRes)):
                _idOld = sortRes[j][0]
                _idNew = sortRes[j][1]
                _dis = sortRes[j][2]
                _val1 = xyzList[_idOld-1]
                _val2 = elementList[_idOld-1]
                # set
                xyzListSorted.append(_val1)
                elementListSorted.append(_val2)
                # all
                matPosition[str(_idNew)] = [_idOld, _idNew, _dis, _val1, _val2]

            # set
            xyzListSorted = np.array(xyzListSorted)

            # bond id conversion
            bondList = np.array(bondList, dtype='i')
            # size
            bondRow = bondList.shape[0]
            # column 0
            bondColumn0 = np.array(bondList[:, 0])
            # column 1
            bondColumn1 = np.array(bondList[:, 1])
            # column 2
            bondColumn2 = np.array(bondList[:, 2])

            # replace
            for i in range(bondRow):
                # column 0
                _v0 = bondColumn0[i]
                # find new value
                _v1 = [item[1] for item in idConversion if item[0] == _v0][0]
                bondColumn0[i] = _v1

                # column 1
                _v2 = bondColumn1[i]
                # find new value
                _v3 = [item[1] for item in idConversion if item[0] == _v2][0]
                bondColumn1[i] = _v3

            # build bond list with new ids
            bondListSorted = np.zeros_like(bondList)
            bondListSorted[:, 0] = bondColumn0
            bondListSorted[:, 1] = bondColumn1
            bondListSorted[:, 2] = bondColumn2

            # set
            idConversion = np.array(idConversion)

            return matPosition, idConversion, xyzListSorted, elementListSorted, bondListSorted

        except Exception as e:
            Exception(e)

    def arrange_prop(self, property_value_list, atom_index_list):
        '''
        Arrange a new list with respect to the index list

        Parameters
        ----------
        property_value_list: list
            such as atomic number
        atom_index_list: list
            atom id between 1 and ...

        Returns
        -------
        res: list
            sorted list
        '''
        try:
            # convert atom id to list id
            index_list = np.array(atom_index_list) - 1
            property_value_list_sorted = np.take(
                property_value_list, index_list)
            # res
            return property_value_list_sorted
        except Exception as e:
            Exception(e)

SetAtomId(xyzList, elementList, bondList)

Set atom id with respect to their position in a 3d frame

Parameters

xyzList : list list of element (atom) position elementList : list list of elements bondList : list list of bond ids and types

Returns

matPosition: list list of new ids xyzListSorted : list list of element (atom) position elementListSorted : list list of elements bondListSorted : list list of bond ids and types

Source code in molvizr3d/docs/molparser.py
def SetAtomId(self, xyzList, elementList, bondList):
    '''
    Set atom id with respect to their position in a 3d frame

    Parameters
    ----------
    xyzList : list
        list of element (atom) position
    elementList : list
        list of elements
    bondList : list
        list of bond ids and types

    Returns
    -------
    matPosition: list
        list of new ids
    xyzListSorted : list
        list of element (atom) position
    elementListSorted : list
        list of elements
    bondListSorted : list
        list of bond ids and types
    '''
    try:
        # robs position
        robs = OBS_POSITIONS
        # res
        disRes = []
        # calculate distance
        for i in range(len(xyzList)):
            _dis = np.linalg.norm(
                np.array(robs) - np.array(xyzList[i]))
            _idOld = int(i+1)
            _symbol = elementList[i]
            disRes.append([_idOld, _dis, _symbol])

        # sort
        sortRes = sorted(disRes, key=lambda l: l[1], reverse=True)

        # reverse [old id, distance, symbol]
        sortRes.reverse()

        # save new id [old id, new id, distance, symbol]
        for j in range(len(sortRes)):
            _idNew = int(j+1)
            sortRes[j].insert(1, _idNew)

        # sorted id (old id, new id)
        idConversion = []
        for j in range(len(sortRes)):
            idConversion.append([sortRes[j][0], sortRes[j][1]])

        # build xyzList and elementlist with respect to the new ids
        xyzListSorted = []
        elementListSorted = []
        matPosition = {}
        for j in range(len(sortRes)):
            _idOld = sortRes[j][0]
            _idNew = sortRes[j][1]
            _dis = sortRes[j][2]
            _val1 = xyzList[_idOld-1]
            _val2 = elementList[_idOld-1]
            # set
            xyzListSorted.append(_val1)
            elementListSorted.append(_val2)
            # all
            matPosition[str(_idNew)] = [_idOld, _idNew, _dis, _val1, _val2]

        # set
        xyzListSorted = np.array(xyzListSorted)

        # bond id conversion
        bondList = np.array(bondList, dtype='i')
        # size
        bondRow = bondList.shape[0]
        # column 0
        bondColumn0 = np.array(bondList[:, 0])
        # column 1
        bondColumn1 = np.array(bondList[:, 1])
        # column 2
        bondColumn2 = np.array(bondList[:, 2])

        # replace
        for i in range(bondRow):
            # column 0
            _v0 = bondColumn0[i]
            # find new value
            _v1 = [item[1] for item in idConversion if item[0] == _v0][0]
            bondColumn0[i] = _v1

            # column 1
            _v2 = bondColumn1[i]
            # find new value
            _v3 = [item[1] for item in idConversion if item[0] == _v2][0]
            bondColumn1[i] = _v3

        # build bond list with new ids
        bondListSorted = np.zeros_like(bondList)
        bondListSorted[:, 0] = bondColumn0
        bondListSorted[:, 1] = bondColumn1
        bondListSorted[:, 2] = bondColumn2

        # set
        idConversion = np.array(idConversion)

        return matPosition, idConversion, xyzListSorted, elementListSorted, bondListSorted

    except Exception as e:
        Exception(e)

__find_element_symbol(atomic_numbers)

Return element symbols

Parameters

atomic_numbers : list atomic numbers

Returns

res : dict a list of all count atomList : list atom list

Source code in molvizr3d/docs/molparser.py
def __find_element_symbol(self, atomic_numbers):
    '''
    Return element symbols

    Parameters
    ----------
    atomic_numbers : list
        atomic numbers

    Returns
    -------
    res : dict
        a list of all count
    atomList : list
        atom list
    '''
    el = Element()
    # loop
    res = el.find_atom_by_property('AtomicNumber', atomic_numbers)

    # interpret
    atomList = [item['symbol'] for item in res]

    # res
    return res, atomList

__json_atom_analyzer(atomNo, bondNo, elementList, xyzList, bondMatrix)

Define xyz list and bond list

Parameters

atomNo : int atom number bondNo : int bond number elementList : list element list xyzList : np.array xyz list bondMatrix : np.array bond matrix

Returns

atomDetails : list atom details objectBaseCoordinate : list object base coordinate bondDetails : list bond details

Source code in molvizr3d/docs/molparser.py
def __json_atom_analyzer(self, atomNo, bondNo, elementList, xyzList, bondMatrix):
    '''
    Define xyz list and bond list

    Parameters
    ----------
    atomNo : int
        atom number
    bondNo : int
        bond number
    elementList : list
        element list
    xyzList : np.array
        xyz list
    bondMatrix : np.array
        bond matrix

    Returns
    -------
    atomDetails : list
        atom details
    objectBaseCoordinate : list
        object base coordinate
    bondDetails : list
        bond details
    '''
    # vars
    # *** detail about atoms
    atomDetails = []

    # element symbols
    atomList = elementList

    # atoms position
    for i in range(atomNo):
        _atomRow = xyzList[i, :]
        # position
        _x = float(_atomRow[0])
        _y = float(_atomRow[1])
        _z = float(_atomRow[2])
        # name
        _name = atomList[i]

        # atom info
        atom = {
            'id': i,
            'symbol': _name,
            'index': i,
            'x': _x,
            'y': _y,
            'z': _z,
            'position': {
                'x': _x,
                'y': _y,
                'z': _z
            },
            'xyz': [_x, _y, _z]
        }
        # save atom info
        atomDetails.append(atom)

    # object base
    objectBaseCoordinate = Structure.CenterPoints(xyzList)
    # print(f"objectBaseCoordinate: {objectBaseCoordinate}")

    # move to the center [0,0,0]
    xyzCenterList, movingCoordinate = Structure.CenterObject(
        xyzList, objectBaseCoordinate)
    # print(f"xyzCenterList: {xyzCenterList} \n movingCoordinate: \n {movingCoordinate}")

    # bond analysis
    bondBlock = []
    atomBonds = []

    # atomNo: *** atom id in the structure ***
    for i in range(atomNo):
        # name
        _nameAtom1 = str(atomList[i])
        # index [not duplicated element]
        # _nameAtom1Index = atomList.index(_nameAtom1)
        _nameAtom1Index = i+1
        # check bond type
        for j in range(bondNo):
            _bondRow = bondMatrix[j, :]
            _nameAtomBondRow = int(_bondRow[0])
            # check bond exist
            if _nameAtom1Index == _nameAtomBondRow:
                # atom 2 index
                _indexAtom2 = int(_bondRow[1])
                # atom 2 name
                _nameAtom2 = str(atomList[_indexAtom2-1])
                # bound type
                _bondType = int(_bondRow[2])
                # str bond
                _bondName = _nameAtom1 + '-' + _nameAtom2
                # str id bond
                _bondId = str(_nameAtom1Index) + '-' + str(_indexAtom2)
                # atom bond
                atomBonds.append(
                    (_indexAtom2, _nameAtom2, _bondName, _bondType, _bondId))

        if len(atomBonds) > 0:
            # save
            _bondList = {
                'id': _nameAtom1Index,
                'symbol': _nameAtom1,
                'bonds': atomBonds
            }
            bondBlock.append(_bondList)

        # reset
        atomBonds = []
        _bondList = {}

    # result
    return atomDetails, bondBlock, xyzCenterList

__json_atom_bondblock(atomNo, bondNo, elementList, bondMatrix)

Build bond block which is used by mat view to display mat structure

Parameters

atomNo : int atom number bondNo : int bond number elementList : list element list bondMatrix : np.array bond matrix

Returns

res : dict a list of all count

Source code in molvizr3d/docs/molparser.py
def __json_atom_bondblock(self, atomNo, bondNo, elementList, bondMatrix):
    '''
    Build bond block which is used by mat view to display mat structure

    Parameters
    ----------
    atomNo : int
        atom number
    bondNo : int
        bond number
    elementList : list
        element list
    bondMatrix : np.array
        bond matrix

    Returns
    -------
    res : dict
        a list of all count
    '''
    try:
        # element symbols
        atomList = elementList

        # bond analysis
        bondBlock = []
        atomBonds = []

        # atomNo: *** atom id in the structure ***
        for i in range(atomNo):
            # name
            _nameAtom1 = str(atomList[i])
            # index [not duplicated element]
            _nameAtom1Index = int(i+1)
            # check bond type
            for j in range(bondNo):
                # name
                _bondRow = bondMatrix[j, :]
                # atom id
                _nameAtomBondRow = int(_bondRow[0])
                # check bond exist
                if _nameAtom1Index == _nameAtomBondRow:
                    # atom 2 index
                    _indexAtom2 = int(_bondRow[1])
                    # atom 2 name
                    _nameAtom2 = str(atomList[_indexAtom2-1])
                    # bound type
                    _bondType = int(_bondRow[2])
                    # str bond
                    _bondName = _nameAtom1 + '-' + _nameAtom2
                    # str id bond
                    _bondId = str(_nameAtom1Index) + '-' + str(_indexAtom2)
                    # atom bond
                    atomBonds.append(
                        (_indexAtom2, _nameAtom2, _bondName, _bondType, _bondId))

            if len(atomBonds) > 0:
                # save
                _bondList = {
                    'id': _nameAtom1Index,
                    'symbol': _nameAtom1,
                    'bonds': atomBonds
                }
                bondBlock.append(_bondList)

            # reset
            atomBonds = []
            _bondList = {}

        # res
        res = {
            'elementList': elementList,
            'bondMatrix': bondMatrix,
            'bondBlock': bondBlock
        }

        # res
        return res
    except Exception as e:
        Exception(e)

__json_atom_position(atomNo, elementList, xyzList)

Set mat position into the center of cartesian coordination

Parameters

atomNo : int atom number elementList : list element list xyzList : np.array xyz list

Returns

res : dict a list of all count

Source code in molvizr3d/docs/molparser.py
def __json_atom_position(self, atomNo, elementList, xyzList):
    '''
    Set mat position into the center of cartesian coordination

    Parameters
    ----------
    atomNo : int
        atom number
    elementList : list
        element list
    xyzList : np.array
        xyz list

    Returns
    -------
    res : dict
        a list of all count
    '''
    try:
        # vars
        # *** detail about atoms
        atomDetails = []

        # element symbols
        atomList = elementList

        # atoms position
        for i in range(atomNo):
            _atomRow = xyzList[i, :]
            # position
            _x = float(_atomRow[0])
            _y = float(_atomRow[1])
            _z = float(_atomRow[2])
            # name
            _name = atomList[i]

            # atom info
            atom = {
                'id': i,
                'symbol': _name,
                'index': i,
                'x': _x,
                'y': _y,
                'z': _z,
                'position': {
                    'x': _x,
                    'y': _y,
                    'z': _z
                },
                'xyz': [_x, _y, _z]
            }
            # save atom info
            atomDetails.append(atom)

        # object base
        objectBaseCoordinate = Structure.CenterPoints(xyzList)

        # move to the center [0,0,0]
        xyzCenterList, movingCoordinate = Structure.CenterObject(
            xyzList, objectBaseCoordinate)

        # res
        res = {
            'atomDetails': atomDetails,
            'elementList': elementList,
            'xyzList': xyzList,
            'xyzCenterList': xyzCenterList,
            'movingCoordinate': movingCoordinate
        }

        # res
        return res
    except Exception as e:
        raise Exception(e)

__json_parser_atoms(data)

Return atom id, atom atomic number

Parameters

data : dict json data

Returns

_aid : int atom id _elementAtomicNumber : int atom atomic number

Source code in molvizr3d/docs/molparser.py
def __json_parser_atoms(self, data):
    '''
    Return atom id, atom atomic number

    Parameters
    ----------
    data : dict
        json data

    Returns
    -------
    _aid : int
        atom id
    _elementAtomicNumber : int
        atom atomic number
    '''
    # aid (atom id)
    _aid = data['aid']
    # element (atomic number)
    _elementAtomicNumber = data['element']
    return _aid, _elementAtomicNumber

__json_parser_bonds(data)

Return atom1 id, atom2 is, bond type

Parameters

data : dict json data

Returns

_aid1 : int atom1 id _aid2 : int atom2 id _order : int bond type

Source code in molvizr3d/docs/molparser.py
def __json_parser_bonds(self, data):
    '''
    Return atom1 id, atom2 is, bond type

    Parameters
    ----------
    data : dict
        json data

    Returns
    -------
    _aid1 : int
        atom1 id
    _aid2 : int
        atom2 id
    _order : int
        bond type
    '''
    # aid1 (atom id)
    _aid1 = data['aid1']
    # aid2 (atom id)
    _aid2 = data['aid2']
    # order
    _order = data['order']

    # transform
    bondMatrix = np.array([_aid1, _aid2, _order])
    bondMatrix = np.transpose(bondMatrix)

    return _aid1, _aid2, _order, bondMatrix

__json_parser_charge(data)

Get charge

Parameters

data : dict json data

Returns

node : int charge

Source code in molvizr3d/docs/molparser.py
def __json_parser_charge(self, data):
    '''
    Get charge

    Parameters
    ----------
    data : dict
        json data

    Returns
    -------
    node : int
        charge
    '''
    # *** id node
    node = data
    return node

__json_parser_coords(data)

Return coordination type, coordination id, xyzList

Parameters

data : dict json data

Returns

_coords_type : str coordination type _coords_aid : int coordination id xyzList : np.array xyzList structureType : str 2d or 3d

Source code in molvizr3d/docs/molparser.py
def __json_parser_coords(self, data):
    '''
    Return coordination type, coordination id, xyzList

    Parameters
    ----------
    data : dict
        json data

    Returns
    -------
    _coords_type : str
        coordination type
    _coords_aid : int
        coordination id
    xyzList : np.array
        xyzList
    structureType : str
        2d or 3d
    '''
    data = data[0]
    _coords_type = data['type']  # list
    _coords_aid = data['aid']  # list
    _coords_conformers = data['conformers'][0]
    _x = _coords_conformers.get('x')
    # atomNo
    atomNo = len(_x)
    _y = _coords_conformers.get('y')

    _z = _coords_conformers.get('z') if _coords_conformers.get(
        'z') is not None else np.zeros(atomNo)
    # transform
    xyzList = np.array([_x, _y, _z])
    xyzList = np.transpose(xyzList)

    # 2d/3d structure
    structureType = "2d" if np.count_nonzero(_z) == 0 else '3d'

    return _coords_type, _coords_aid, xyzList, structureType

__json_parser_count(data)

Return a list of all count

Parameters

data : dict json data

Returns

res : dict a list of all count

Source code in molvizr3d/docs/molparser.py
def __json_parser_count(self, data):
    '''
    Return a list of all count

    Parameters
    ----------
    data : dict
        json data

    Returns
    -------
    res : dict
        a list of all count
    '''
    res = {}
    for key, value in data.items():
        res[key] = value
    return res

__json_parser_id(data)

Return cid

Parameters

data : dict json data

Returns

node : int cid

Source code in molvizr3d/docs/molparser.py
def __json_parser_id(self, data):
    '''
    Return cid 

    Parameters
    ----------
    data : dict
        json data

    Returns
    -------
    node : int
        cid
    '''
    # *** id node
    node = data['id']['cid']
    return node

__json_parser_props(data)

Return a list of all properties

Parameters

data : dict json data

Returns

res : dict a list of all properties

Source code in molvizr3d/docs/molparser.py
def __json_parser_props(self, data):
    '''
    Return a list of all properties

    Parameters
    ----------
    data : dict
        json data

    Returns
    -------
    res : dict
        a list of all properties
    '''
    res = {}
    for i in range(len(data)):
        _keySet = data[i]['urn']['label']
        _valueSet = list(data[i]['value'].values())
        res[str(_keySet)] = _valueSet[0]

    return res

__var_analyzer(data)

Make a dict of all properties

Parameters

data : str sdf data

Returns

res : dict a list of all count

Source code in molvizr3d/docs/molparser.py
def __var_analyzer(data):
    '''
    Make a dict of all properties

    Parameters
    ----------
    data : str
        sdf data

    Returns
    -------
    res : dict
        a list of all count
    '''
    res = {}
    dataSize = len(data)
    for i in range(dataSize):
        # name
        varName = data[i][1]
        # val
        varVal = (data[i][2]).split('\n')
        varVal = [item.strip() for item in varVal]
        varVal = list(filter(None, varVal))

        # check
        if len(varVal) == 1:
            _varVal = str(varVal[0])
        else:
            _varVal = varVal
        # set
        _keySet = str(varName)
        _valueSet = _varVal
        # res
        res[_keySet] = _valueSet
        # reset

    return res

__var_finder(data)

Find variables in a sdf file (single)

Parameters

data : str sdf data

Returns

res : dict a list of all count

Source code in molvizr3d/docs/molparser.py
def __var_finder(data):
    '''
    Find variables in a sdf file (single)

    Parameters
    ----------
    data : str
        sdf data

    Returns
    -------
    res : dict
        a list of all count
    '''
    res = re.findall(
        r"(\>\s*\<(.*)\s*\>\s*((.*\n)([^\<\>\$\$\$\$])*))", data, re.M)
    return res

arrange_prop(property_value_list, atom_index_list)

Arrange a new list with respect to the index list

Parameters

property_value_list: list such as atomic number atom_index_list: list atom id between 1 and ...

Returns

res: list sorted list

Source code in molvizr3d/docs/molparser.py
def arrange_prop(self, property_value_list, atom_index_list):
    '''
    Arrange a new list with respect to the index list

    Parameters
    ----------
    property_value_list: list
        such as atomic number
    atom_index_list: list
        atom id between 1 and ...

    Returns
    -------
    res: list
        sorted list
    '''
    try:
        # convert atom id to list id
        index_list = np.array(atom_index_list) - 1
        property_value_list_sorted = np.take(
            property_value_list, index_list)
        # res
        return property_value_list_sorted
    except Exception as e:
        Exception(e)

json_parser(jsonSource, id_sort=True)

parse json file

Parameters

jsonSource: dict file json file content id_sort: bool if True, sort id

Returns

res: dict

Source code in molvizr3d/docs/molparser.py
def json_parser(self, jsonSource, id_sort=True):
    '''
    parse json file

    Parameters
    ----------
    jsonSource: dict file
        json file content
    id_sort: bool
        if True, sort id

    Returns
    -------
    res: dict
    '''
    try:
        dictSource = jsonSource['PC_Compounds'][0]

        # analyze json file
        # *** id node
        if 'id' in dictSource:
            _idNode = dictSource['id']
            cid = self.__json_parser_id(_idNode)

        # *** atoms
        if 'atoms' in dictSource:
            _atomsNode = dictSource['atoms']
            # atom ids, element atomic number
            atomIds, _elementAtomicNumber = self.__json_parser_atoms(
                _atomsNode)

        # atom numbers
        atomNo = len(atomIds)

        # atom list (element list)
        elementListRes, elementList = self.__find_element_symbol(
            _elementAtomicNumber)

        # *** bonds
        if 'bonds' in dictSource:
            _bonds = dictSource['bonds']
            # atom1 id, atom2 id, bond types
            atomId1, atomId2, bondTypes, bondMatrix = self.__json_parser_bonds(
                _bonds)

        # bond numbers
        bondNo = len(atomId1)

        # *** coords
        if 'coords' in dictSource:
            _coords = dictSource['coords']  # list
            # coords type, aid, xyzList
            coords_type, coords_aid, xyzList, structure_type = self.__json_parser_coords(
                _coords)

        # *** charge
        if 'charge' in dictSource:
            _charge = dictSource['charge']  # scaler
            charge = self.__json_parser_charge(_charge)

        # *** props
        if 'props' in dictSource:
            _props = dictSource['props']  # list of dict
            propDict = self.__json_parser_props(_props)

        # *** count
        if 'count' in dictSource:
            _count = dictSource['count']  # dict
            countList = self.__json_parser_count(_count)

        # interpret
        __json_atom_position_res = self.__json_atom_position(
            atomNo, elementList, xyzList)

        # bond block
        __json_atom_bondblock_res = self.__json_atom_bondblock(
            atomNo, bondNo, elementList, bondMatrix)

        # bondBlock: used for Matview class
        # atomDetails, bondBlock, xyzCenterList = self.__json_atom_analyzer(
        #     atomNo, bondNo, elementList, xyzList, bondMatrix)

        # *** origin info
        origin_info = {
            'atom_elements': __json_atom_position_res.get('elementList'),
            'atom_atomic_number': _elementAtomicNumber,
            'atom_details': __json_atom_position_res.get('atomDetails'),
            'bond_block': __json_atom_bondblock_res.get('bondBlock'),
            'bond_list': __json_atom_bondblock_res.get('bondMatrix'),
            'xyz_list': __json_atom_position_res.get('xyzList'),
            'xyz_center_list': __json_atom_position_res.get('xyzCenterList'),
        }

        # *** define new ids for mat and update
        # *** xyzList, bondMatrix, elementlist, elementAtomicNumber
        # *** bond_list = bondMatrix
        # *** atom_block = atom_details
        # if id_sort:
        mat_position_info, atom_id_conversion, xyz_list_sorted, \
            element_list_sorted, bond_list_sorted = self.SetAtomId(
                xyzList, elementList, bondMatrix)

        # interpret
        __json_atom_position_res2 = self.__json_atom_position(
            atomNo, element_list_sorted, xyz_list_sorted)
        # set
        atom_block_sorted = __json_atom_position_res2.get('atomDetails')
        xyz_list_sorted = __json_atom_position_res2.get('xyzList')
        xyz_center_list_sorted = __json_atom_position_res2.get(
            'xyzCenterList')

        # bond block
        __json_atom_bondblock_res2 = self.__json_atom_bondblock(
            atomNo, bondNo, element_list_sorted, bond_list_sorted)
        # set
        bond_block_sorted = __json_atom_bondblock_res2.get('bondBlock')

        # atomic number sorted
        element_atomic_number = self.arrange_prop(
            _elementAtomicNumber, atom_id_conversion[:, 0])

        # update properties
        # name
        mat_name = propDict.get('IUPAC Name')
        if mat_name is None:
            mat_name = 'NULL'

        # formula
        mat_formula = propDict.get('Molecular Formula')
        if mat_formula is None:
            # create mat formula
            mat_formula = 'NULL'

        # molecular weight
        mat_mass = propDict.get('Molecular Weight')
        if mat_mass is None:
            # mat molecular weight/mass
            mat_mass = 0
        else:
            mat_mass = float(mat_mass)

        # res
        res = {
            'header_block': '',
            'counts_line': '',
            'mat_structure': structure_type,
            'mat_cid': cid,
            'mat_name': mat_name,
            'mat_formula': mat_formula,
            'mat_mass': mat_mass,
            'atom_numbers': atomNo,
            'atom_elements': element_list_sorted,
            'atom_atomic_number': element_atomic_number,
            'atom_block': atom_block_sorted,
            'bond_numbers': bondNo,
            'bond_block': bond_block_sorted,
            'bond_list': bond_list_sorted,
            'xyz_list': xyz_list_sorted,
            'xyz_center_list': xyz_center_list_sorted,
            'compound_properties': propDict,
            'mat_info_origin': origin_info
        }

        return res

    except Exception as e:
        raise Exception(e)

read_file(sourceContent={})

Read structure file 1. from file 2. download from api

Parameters

filepath : str full file name with directory

Returns

res : dict mol: mol object structure: structure object

hints

mol: mol object header_block: header block counts_line: counts line atom_numbers: atom number mat_cid: cid number mat_name: IUPAC name mat_formula: formula mat_mass: molecular mass atom_names: atom list atom_xyz: atom coordinate bond_numbers: bond number bond_list: bond list bond_matrix: bond matrix bond_xyz: bond coordinate

structure: structure object mol: mol object mat: mat object

Source code in molvizr3d/docs/molparser.py
def read_file(self, sourceContent={}):
    '''
    Read structure file 
        1. from file
        2. download from api

    Parameters
    ----------
    filepath : str
        full file name with directory 

    Returns
    -------
    res : dict
        mol: mol object
        structure: structure object

    hints:
        mol: mol object
            header_block: header block
            counts_line: counts line
            atom_numbers: atom number
            mat_cid: cid number
            mat_name: IUPAC name
            mat_formula: formula
            mat_mass: molecular mass
            atom_names: atom list
            atom_xyz: atom coordinate
            bond_numbers: bond number
            bond_list: bond list
            bond_matrix: bond matrix
            bond_xyz: bond coordinate

        structure: structure object
            mol: mol object
            mat: mat object
    '''
    try:
        # get file path
        filePath = self.filepath

        # check
        if filePath:
            # open file and get content
            fileContent, fileDir, fileName, fileFormat = Utility.OpenFile(
                filePath)
        else:
            # read string/json and ... files
            fileContent, fileFormat = Utility.ReadContent(
                sourceContent)

        # method selection
        parserFun = {
            'sdf': self.sdf_parser,
            'json': self.json_parser
        }

        # parse file
        parserSelection = parserFun.get(fileFormat)
        parserRes = parserSelection(fileContent)
        return parserRes

    except Exception as e:
        raise Exception(e)

sdf_parser(sdfSource, sdfVersion='V2000')

Parse sdf file

Parameters

sdfSource : str sdf file content

str

sdf file version (default V2000)

Returns

res : dict mol: mol object header_block: header block counts_line: counts line atom_numbers: atom number mat_cid: cid number mat_name: IUPAC name mat_formula: formula mat_mass: molecular mass atom_names: atom list atom_elements: atom list bond_numbers: bond number atom_block: atoms bond_block: bond list xyz_list: xyz list xyz_center_list: xyz center list compound_properties: compound properties

Source code in molvizr3d/docs/molparser.py
def sdf_parser(self, sdfSource, sdfVersion='V2000'):
    '''
    Parse sdf file

    Parameters
    ----------
    sdfSource : str
        sdf file content

    sdfVersion : str
        sdf file version (default V2000)

    Returns
    -------
    res : dict
        mol: mol object
            header_block: header block
            counts_line: counts line
            atom_numbers: atom number
            mat_cid: cid number
            mat_name: IUPAC name
            mat_formula: formula
            mat_mass: molecular mass
            atom_names: atom list
            atom_elements: atom list
            bond_numbers: bond number
            atom_block: atoms
            bond_block: bond list
            xyz_list: xyz list
            xyz_center_list: xyz center list
            compound_properties: compound properties

    '''
    # decode binary
    # if binary file
    # sdfSource = sdfSource.decode('utf-8')
    # if text file
    sdfSource = sdfSource
    # create list
    sdfSourceList = sdfSource.splitlines()

    # header block
    headerBlock = sdfSourceList[0:3]

    # counts line
    countsLine = sdfSourceList[3]
    if countsLine.find('V2000') == -1:
        raise Exception(
            'SDF file version is not compatible with this method, import 2000 version.')
    # check
    countsLineList = countsLine.split()

    # find 'M END'
    MENDi = -1
    MENDi = sdfSourceList.index('M  END')
    # connection table
    if MENDi != -1:
        connectionTable = sdfSourceList[4:MENDi]

    # *** check
    _countsLineListSize = len(countsLineList)
    if _countsLineListSize == 10:
        # atom no
        atomNo = int(countsLineList[0])
        # bond no
        bondNo = int(countsLineList[1])
    elif _countsLineListSize == 9:
        _connectionTableLines = connectionTable
        _connectionTableLinesSize = len(_connectionTableLines)
        # first record
        _firstRecord = _connectionTableLines[0]
        _firstRecordSize = len(_firstRecord)
        _secondRecord = _connectionTableLines[0]
        _secondRecordSize = len(_secondRecord)
        if _firstRecordSize != _secondRecordSize:
            raise Exception('sdf file is not coded correctly.')
        # loop
        for l in range(_connectionTableLinesSize):
            _loopRecordSize = len(_connectionTableLines[l])
            if _loopRecordSize < _firstRecordSize:
                # atom no
                atomNo = int(l)
                # bond no
                bondNo = int(str(countsLineList[0]).split(str(atomNo))[1])
                # break
                break
    else:
        raise Exception('3rd line of the sdf file is not coded correctly.')

    # element rows
    elementRows = connectionTable[0:atomNo]
    # bond rows
    bondRows = connectionTable[atomNo:]

    # other vars
    compoundPropertiesList = MolParser.__var_finder(sdfSource)
    # dict vars
    compoundProperties = MolParser.__var_analyzer(compoundPropertiesList)
    # extract:
    PUBCHEM_COMPOUND_CID = compoundProperties.get('PUBCHEM_COMPOUND_CID')
    PUBCHEM_IUPAC_NAME = compoundProperties.get('PUBCHEM_IUPAC_NAME')
    PUBCHEM_EXACT_MASS = compoundProperties.get('PUBCHEM_EXACT_MASS')
    PUBCHEM_MOLECULAR_FORMULA = compoundProperties.get(
        'PUBCHEM_MOLECULAR_FORMULA')
    PUBCHEM_MOLECULAR_WEIGHT = compoundProperties.get(
        'PUBCHEM_MOLECULAR_WEIGHT')

    atoms = []
    atomList = []
    xyzList = []

    # atoms position
    for i in range(atomNo):
        _atomRow = elementRows[i].split()
        # position
        _x = float(_atomRow[0])
        _y = float(_atomRow[1])
        _z = float(_atomRow[2])
        # name
        _name = _atomRow[3]

        # atom list
        atomList.append(_name)

        # atom info
        atom = {
            'id': i+1,
            'symbol': _name,
            'index': i+1,
            'x': _x,
            'y': _y,
            'z': _z,
            'position': {
                'x': _x,
                'y': _y,
                'z': _z
            },
            'xyz': [_x, _y, _z]
        }
        # save atom info
        atoms.append(atom)
        # xyz
        xyzList.append([_x, _y, _z])

    # set
    xyzList = np.array(xyzList)

    # object base
    objectBaseCoordinate = Structure.CenterPoints(xyzList)
    # print(f"objectBaseCoordinate: {objectBaseCoordinate}")

    # move to the center [0,0,0]
    xyzCenterList, movingCoordinate = Structure.CenterObject(
        xyzList, objectBaseCoordinate)
    # print(f"xyzCenterList: {xyzCenterList} \n movingCoordinate: \n {movingCoordinate}")

    # create mat formula
    matFormula = Structure.create_formula(atomList)
    # calculate molecular mass
    # matMass = 1

    # bond analysis
    bondList = []
    atomBonds = []

    # atomNo: *** atom id in the structure ***
    for i in range(atomNo):
        # name
        _nameAtom1 = str(atomList[i])
        # index [not duplicated element]
        # _nameAtom1Index = atomList.index(_nameAtom1)
        _nameAtom1Index = i+1
        # check bond type
        for j in range(bondNo):
            _bondRow = bondRows[j].split()
            # starts from 1 to ... (not 0)
            _nameAtomBondRow = int(_bondRow[0])
            # check bond exist
            if _nameAtom1Index == _nameAtomBondRow:
                # atom 2 index
                _indexAtom = int(_bondRow[1])
                # atom 2 name
                _nameAtom2 = str(atomList[_indexAtom-1])
                # bound type
                _bondType = int(_bondRow[2])
                # str bond
                _bondName = _nameAtom1 + _nameAtom2
                # atom bond
                atomBonds.append(
                    (_indexAtom, _nameAtom2, _bondName, _bondType))

        if len(atomBonds) > 0:
            # save
            _bondList = {
                'id': _nameAtom1Index,
                'symbol': _nameAtom1,
                'bonds': atomBonds
            }
            bondList.append(_bondList)

        # reset
        atomBonds = []
        _bondList = {}

    # res
    res = {
        'header_block': headerBlock,
        'counts_line': countsLine,
        'atom_numbers': atomNo,
        'mat_cid': PUBCHEM_COMPOUND_CID,
        'mat_name': PUBCHEM_IUPAC_NAME if PUBCHEM_IUPAC_NAME is not None else '',
        'mat_formula': PUBCHEM_MOLECULAR_FORMULA if PUBCHEM_MOLECULAR_FORMULA is not None else matFormula,
        'mat_mass': PUBCHEM_EXACT_MASS if PUBCHEM_EXACT_MASS is not None else PUBCHEM_MOLECULAR_WEIGHT,
        'atom_names': atomList,
        'atom_elements': atomList,
        'bond_numbers': bondNo,
        'atom_block': atoms,
        'bond_block': bondList,
        'xyz_list': xyzList,
        'xyz_center_list': xyzCenterList,
        'compound_properties': compoundProperties
    }

    # return
    return res

observer

Observer

Source code in molvizr3d/docs/observer.py
class Observer():

    def __init__(self):
        pass

    @staticmethod
    def GenerateCircularObserver(xyzList, obsRadius, dataNo):
        '''
        generate observer points based on circle's track
        '''
        # angular frequency
        freq = 3
        # obs angles
        obsAnglesRes = Structure.PeriodGenerator(dataNo)
        obsAngles = obsAnglesRes[0]
        obsAnglesStep = obsAnglesRes[1]

        # circle loops
        obsAnglesLoopRes = Structure.PeriodGenerator(dataNo, freq)
        obsAnglesLoop = obsAnglesLoopRes[0]
        obsAnglesLoopStep = obsAnglesLoopRes[1]

        # len
        obsAnglesLength = len(obsAngles)
        # observer coordinate
        obsCoordinate = np.zeros((freq, obsAnglesLength, 3))

        # circle 1
        for i in range(obsAnglesLength):
            _x, _y = Structure.CircleCoordinate(obsAngles[i], obsRadius)
            # outside compound
            _obsCoordinate = [_x, _y, 0]
            # inside compound
            # save
            obsCoordinate[0, i, :] = _obsCoordinate
            # reset
            _x, _y = 0, 0

        # circle 2
        for i in range(obsAnglesLength):
            _y, _z = Structure.CircleCoordinate(obsAngles[i], obsRadius)
            # outside compound
            _obsCoordinate = [0, _y, _z]
            # inside compound
            # save
            obsCoordinate[1, i, :] = _obsCoordinate
            # reset
            _y, _z = 0, 0

        # circle 3
        for i in range(obsAnglesLength):
            _x, _z = Structure.CircleCoordinate(obsAngles[i], obsRadius)
            # outside compound
            _obsCoordinate = [_x, 0, _z]
            # inside compound
            # save
            obsCoordinate[2, i, :] = _obsCoordinate
            # reset
            _x, _z = 0, 0

        # res
        return obsCoordinate, obsAngles, obsAnglesLoop, obsAnglesLoopStep

    @staticmethod
    def GeneratorLinearObserver(xyzList, obsDistance, dataNo):
        # number of observers
        obsNo = 3
        # obs length
        obsLengthRes = Structure.LineGenerator(dataNo)
        obsLength = obsLengthRes[0]
        obsLengthStep = obsLengthRes[1]

        # obs total length
        obsLengthLoopRes = Structure.LineGenerator(dataNo, w=obsNo)
        obsLengthLoop = obsLengthLoopRes[0]
        obsLengthLoopStep = obsLengthLoopRes[1]

        # len
        obsLengthSize = len(obsLength)
        # observer cordinate
        obsCoordinate = np.zeros((obsNo, obsLengthSize, 3))

        # line 1 (parallel x)
        for i in range(obsLengthSize):
            _x, _y, _z = obsLength[i], obsDistance, 0
            # outside compound
            _obsCoordinate = [_x, _y, _z]
            # inside compound
            # save
            obsCoordinate[0, i, :] = _obsCoordinate
            # reset
            _x, _y, _z = 0, 0, 0

        # line 2 (parallel y)
        for i in range(obsLengthSize):
            _x, _y, _z = obsDistance, obsLength[i], 0
            # outside compound
            _obsCoordinate = [_x, _y, _z]
            # inside compound
            # save
            obsCoordinate[1, i, :] = _obsCoordinate
            # reset
            _x, _y, _z = 0, 0, 0

        # line 1 (parallel z)
        for i in range(obsLengthSize):
            _x, _y, _z = obsLength[i], 0, obsDistance
            # outside compound
            _obsCoordinate = [_x, _y, _z]
            # inside compound
            # save
            obsCoordinate[2, i, :] = _obsCoordinate
            # reset
            _x, _y, _z = 0, 0, 0

        # res
        return obsCoordinate, obsLength, obsLengthLoop, obsLengthLoopStep

    @staticmethod
    def GeneratorCircleObserver(r, tetaNo, phiNo, limits=[]):
        '''
        Generate circle xyz points in cartesian coordinate
        '''
        # rad [rad]
        tetaRes = Structure.PeriodGenerator(n=tetaNo)
        teta = tetaRes[0]
        tetaStep = tetaRes[1]
        # print(f"teta: {teta.shape}")
        tetaNo = len(teta)
        # phi [rad]
        if len(limits) > 0:
            phiRes = Structure.PeriodLimitGenerator(n=phiNo, limits=limits)
            phi = phiRes[0]
            phiStep = phiRes[1]
        else:
            phiRes = Structure.PeriodGenerator(n=phiNo)
            phi = phiRes[0]
            phiStep = phiRes[1]
        # print(f"phi: {phi.shape}")
        phiNo = len(phi)

        # total rotation
        angFreq = Structure.PeriodGenerator(n=tetaNo, w=tetaNo)[0]
        # print(f"angFreq: {angFreq}")
        # frequency
        freq = np.max(angFreq)/(2*np.pi)
        # print(f"freq: {freq}")
        # period
        period = 1/freq
        # print(f"period: {period}")
        # sample no [in a second]
        sampleNo = len(angFreq)
        # print(f"sampleNo: {sampleNo}")
        # sampling rate [number of samples in a second]
        samplingRate = sampleNo
        # sampling interval
        samplingInterval = 1/samplingRate
        # time span
        timeSpan = np.arange(0, 1, samplingInterval)

        # [number of circles, number of points in a circle, [x,y,z] points]
        xyzPoints = np.zeros((tetaNo, phiNo, 3))

        for i in range(tetaNo):
            for j in range(phiNo):
                _rtpPoint = np.array([r, teta[i], phi[j]])
                _xyzPoint = Structure.SphericalToCartesianCoordinate(_rtpPoint)
                # save
                xyzPoints[i, j, :] = _xyzPoint

        # print(f"xyzPoints: {xyzPoints.shape}")
        # res
        return xyzPoints, teta, phi, tetaStep, phiStep, angFreq, freq, period, sampleNo, samplingRate, samplingInterval, timeSpan

    @staticmethod
    def ObsWatchPathGenerator(r, tetaNo, phiNo, tetaLimits=[], phiLimit=[]):
        '''
        generate a circle path containing xyz points in the cartesian coordinate

        args:
            r: distance between observer points and element points
            tetaNo: number of circle paths
            phiNo: number of observer points in a circle path
            tetaLimits=[]: angles define the limit of observer, default: [0, pi]
            phiLimit=[]: angles define the limit of observer, default: [0, 2pi]

        hints:
            the last obs point is the mirror of angle 0, thus it is ignored.
        '''
        # rad [rad]
        if len(tetaLimits) > 0:
            tetaRes = Structure.PeriodLimitGenerator(
                n=tetaNo+1, limits=tetaLimits)
            teta = tetaRes[0]
            tetaStep = tetaRes[1]
        else:
            tetaRes = Structure.PeriodGenerator(n=tetaNo+1)
            teta = tetaRes[0]
            tetaStep = tetaRes[1]

        # phi [rad]
        if len(phiLimit) > 0:
            phiRes = Structure.PeriodLimitGenerator(
                n=phiNo+1, limits=phiLimit)
            phi = phiRes[0]
            phiStep = phiRes[1]
        else:
            phiRes = Structure.PeriodGenerator(n=phiNo+1)
            phi = phiRes[0]
            phiStep = phiRes[1]

        # time span [for one loop]
        timeLoop = 1
        # sampling no [1 second]
        sampleNo = phiNo
        # sampling rate [number of samples in a second]
        samplingRate = sampleNo
        # sampling interval
        samplingInterval = 1/samplingRate
        # time span
        timeSpan = np.arange(0, timeLoop, samplingInterval)
        # frequency set
        freq = 1
        # total rotation [1 second]
        angFreq = 2*np.pi*freq
        # period
        period = 1/freq

        # total sampling time [s]
        samplingTimeTotal = tetaNo
        # total number of samples (total time)
        sampleNoTotal = samplingTimeTotal*sampleNo
        # sampling rate with respect to total time
        samplingIntervalTotal = samplingTimeTotal/sampleNoTotal
        # time span
        timeSpanTotal = np.arange(0, samplingTimeTotal, samplingIntervalTotal)

        # [number of circles, number of points in a circle, [x,y,z] points]
        xyzPoints = np.zeros((tetaNo, phiNo, 3))

        for i in range(tetaNo):
            for j in range(phiNo):
                _rtpPoint = np.array([r, teta[i], phi[j]])
                _xyzPoint = Structure.SphericalToCartesianCoordinate(_rtpPoint)
                # save
                xyzPoints[i, j, :] = _xyzPoint

        # res
        return xyzPoints, teta, phi, tetaStep, phiStep, angFreq, freq, period, sampleNo, samplingRate, samplingInterval, timeSpan, timeSpanTotal

GenerateCircularObserver(xyzList, obsRadius, dataNo) staticmethod

generate observer points based on circle's track

Source code in molvizr3d/docs/observer.py
@staticmethod
def GenerateCircularObserver(xyzList, obsRadius, dataNo):
    '''
    generate observer points based on circle's track
    '''
    # angular frequency
    freq = 3
    # obs angles
    obsAnglesRes = Structure.PeriodGenerator(dataNo)
    obsAngles = obsAnglesRes[0]
    obsAnglesStep = obsAnglesRes[1]

    # circle loops
    obsAnglesLoopRes = Structure.PeriodGenerator(dataNo, freq)
    obsAnglesLoop = obsAnglesLoopRes[0]
    obsAnglesLoopStep = obsAnglesLoopRes[1]

    # len
    obsAnglesLength = len(obsAngles)
    # observer coordinate
    obsCoordinate = np.zeros((freq, obsAnglesLength, 3))

    # circle 1
    for i in range(obsAnglesLength):
        _x, _y = Structure.CircleCoordinate(obsAngles[i], obsRadius)
        # outside compound
        _obsCoordinate = [_x, _y, 0]
        # inside compound
        # save
        obsCoordinate[0, i, :] = _obsCoordinate
        # reset
        _x, _y = 0, 0

    # circle 2
    for i in range(obsAnglesLength):
        _y, _z = Structure.CircleCoordinate(obsAngles[i], obsRadius)
        # outside compound
        _obsCoordinate = [0, _y, _z]
        # inside compound
        # save
        obsCoordinate[1, i, :] = _obsCoordinate
        # reset
        _y, _z = 0, 0

    # circle 3
    for i in range(obsAnglesLength):
        _x, _z = Structure.CircleCoordinate(obsAngles[i], obsRadius)
        # outside compound
        _obsCoordinate = [_x, 0, _z]
        # inside compound
        # save
        obsCoordinate[2, i, :] = _obsCoordinate
        # reset
        _x, _z = 0, 0

    # res
    return obsCoordinate, obsAngles, obsAnglesLoop, obsAnglesLoopStep

GeneratorCircleObserver(r, tetaNo, phiNo, limits=[]) staticmethod

Generate circle xyz points in cartesian coordinate

Source code in molvizr3d/docs/observer.py
@staticmethod
def GeneratorCircleObserver(r, tetaNo, phiNo, limits=[]):
    '''
    Generate circle xyz points in cartesian coordinate
    '''
    # rad [rad]
    tetaRes = Structure.PeriodGenerator(n=tetaNo)
    teta = tetaRes[0]
    tetaStep = tetaRes[1]
    # print(f"teta: {teta.shape}")
    tetaNo = len(teta)
    # phi [rad]
    if len(limits) > 0:
        phiRes = Structure.PeriodLimitGenerator(n=phiNo, limits=limits)
        phi = phiRes[0]
        phiStep = phiRes[1]
    else:
        phiRes = Structure.PeriodGenerator(n=phiNo)
        phi = phiRes[0]
        phiStep = phiRes[1]
    # print(f"phi: {phi.shape}")
    phiNo = len(phi)

    # total rotation
    angFreq = Structure.PeriodGenerator(n=tetaNo, w=tetaNo)[0]
    # print(f"angFreq: {angFreq}")
    # frequency
    freq = np.max(angFreq)/(2*np.pi)
    # print(f"freq: {freq}")
    # period
    period = 1/freq
    # print(f"period: {period}")
    # sample no [in a second]
    sampleNo = len(angFreq)
    # print(f"sampleNo: {sampleNo}")
    # sampling rate [number of samples in a second]
    samplingRate = sampleNo
    # sampling interval
    samplingInterval = 1/samplingRate
    # time span
    timeSpan = np.arange(0, 1, samplingInterval)

    # [number of circles, number of points in a circle, [x,y,z] points]
    xyzPoints = np.zeros((tetaNo, phiNo, 3))

    for i in range(tetaNo):
        for j in range(phiNo):
            _rtpPoint = np.array([r, teta[i], phi[j]])
            _xyzPoint = Structure.SphericalToCartesianCoordinate(_rtpPoint)
            # save
            xyzPoints[i, j, :] = _xyzPoint

    # print(f"xyzPoints: {xyzPoints.shape}")
    # res
    return xyzPoints, teta, phi, tetaStep, phiStep, angFreq, freq, period, sampleNo, samplingRate, samplingInterval, timeSpan

ObsWatchPathGenerator(r, tetaNo, phiNo, tetaLimits=[], phiLimit=[]) staticmethod

generate a circle path containing xyz points in the cartesian coordinate

Parameters:

Name Type Description Default
r

distance between observer points and element points

required
tetaNo

number of circle paths

required
phiNo

number of observer points in a circle path

required
tetaLimits=[]

angles define the limit of observer, default: [0, pi]

required
phiLimit=[]

angles define the limit of observer, default: [0, 2pi]

required
hints

the last obs point is the mirror of angle 0, thus it is ignored.

Source code in molvizr3d/docs/observer.py
@staticmethod
def ObsWatchPathGenerator(r, tetaNo, phiNo, tetaLimits=[], phiLimit=[]):
    '''
    generate a circle path containing xyz points in the cartesian coordinate

    args:
        r: distance between observer points and element points
        tetaNo: number of circle paths
        phiNo: number of observer points in a circle path
        tetaLimits=[]: angles define the limit of observer, default: [0, pi]
        phiLimit=[]: angles define the limit of observer, default: [0, 2pi]

    hints:
        the last obs point is the mirror of angle 0, thus it is ignored.
    '''
    # rad [rad]
    if len(tetaLimits) > 0:
        tetaRes = Structure.PeriodLimitGenerator(
            n=tetaNo+1, limits=tetaLimits)
        teta = tetaRes[0]
        tetaStep = tetaRes[1]
    else:
        tetaRes = Structure.PeriodGenerator(n=tetaNo+1)
        teta = tetaRes[0]
        tetaStep = tetaRes[1]

    # phi [rad]
    if len(phiLimit) > 0:
        phiRes = Structure.PeriodLimitGenerator(
            n=phiNo+1, limits=phiLimit)
        phi = phiRes[0]
        phiStep = phiRes[1]
    else:
        phiRes = Structure.PeriodGenerator(n=phiNo+1)
        phi = phiRes[0]
        phiStep = phiRes[1]

    # time span [for one loop]
    timeLoop = 1
    # sampling no [1 second]
    sampleNo = phiNo
    # sampling rate [number of samples in a second]
    samplingRate = sampleNo
    # sampling interval
    samplingInterval = 1/samplingRate
    # time span
    timeSpan = np.arange(0, timeLoop, samplingInterval)
    # frequency set
    freq = 1
    # total rotation [1 second]
    angFreq = 2*np.pi*freq
    # period
    period = 1/freq

    # total sampling time [s]
    samplingTimeTotal = tetaNo
    # total number of samples (total time)
    sampleNoTotal = samplingTimeTotal*sampleNo
    # sampling rate with respect to total time
    samplingIntervalTotal = samplingTimeTotal/sampleNoTotal
    # time span
    timeSpanTotal = np.arange(0, samplingTimeTotal, samplingIntervalTotal)

    # [number of circles, number of points in a circle, [x,y,z] points]
    xyzPoints = np.zeros((tetaNo, phiNo, 3))

    for i in range(tetaNo):
        for j in range(phiNo):
            _rtpPoint = np.array([r, teta[i], phi[j]])
            _xyzPoint = Structure.SphericalToCartesianCoordinate(_rtpPoint)
            # save
            xyzPoints[i, j, :] = _xyzPoint

    # res
    return xyzPoints, teta, phi, tetaStep, phiStep, angFreq, freq, period, sampleNo, samplingRate, samplingInterval, timeSpan, timeSpanTotal

structure

Structure

chemical structure methods

Source code in molvizr3d/docs/structure.py
class Structure():
    '''
    chemical structure methods
    '''

    def __init__(self):
        pass

    @staticmethod
    def CenterPoints(xyzList):
        '''
        find the center coordination of an object
        '''
        # set
        xyzList = np.array(xyzList)
        # find the highest xyz
        # x
        xMax = np.max(xyzList[:, 0])
        xMin = np.min(xyzList[:, 0])
        if np.abs(xMax) != np.abs(xMin):
            xLen = np.abs(xMax - xMin)
            xCenter = xMin + (xLen/2)
        else:
            xLen = 0
            xCenter = 0 + (xLen/2)
        # print(f"X value: {xMin}, {xMax}")

        # y
        yMax = np.max(xyzList[:, 1])
        yMin = np.min(xyzList[:, 1])
        if np.abs(yMax) != np.abs(yMin):
            yLen = np.abs(yMax - yMin)
            yCenter = yMin + (yLen/2)
        else:
            yLen = 0
            yCenter = 0 + (yLen/2)
        # print(f"Y value: {yMin}, {yMax}")

        # z
        zMax = np.max(xyzList[:, 2])
        zMin = np.min(xyzList[:, 2])
        if np.abs(zMax) != np.abs(zMin):
            zLen = np.abs(zMax - zMin)
            zCenter = zMin + (zLen/2)
        else:
            zLen = 0
            zCenter = 0 + (zLen/2)
        # print(f"Z value: {zMin}, {zMax}")

        # object base
        objectBaseCoordinate = np.array([xCenter, yCenter, zCenter])

        return objectBaseCoordinate

    @staticmethod
    def CenterObject(xyzList, centerPoint):
        '''
        move an object to the center of the origin [0,0,0]
        '''
        originPoint = np.array([0, 0, 0])
        movingCoordinate = originPoint - centerPoint
        newCenterPoints = np.array(xyzList) + movingCoordinate

        return newCenterPoints, movingCoordinate

    @staticmethod
    def ObjectDislay(xyzList, xyzCenterList):
        '''
        display object in two places
        '''
        # find the center of object
        xyzCenter = Structure.CenterPoints(xyzList)
        # find the center of object after moving to the origin [0,0,0]
        xyzCenterMoving = Structure.CenterPoints(xyzCenterList)

        # 3d plot
        fig = plt.figure()
        ax = plt.axes(projection='3d')
        ax.scatter3D(xyzList[:, 0], xyzList[:, 1], xyzList[:, 2])
        ax.scatter3D(xyzCenter[0], xyzCenter[1], xyzCenter[2])
        ax.scatter3D(xyzCenterList[:, 0],
                     xyzCenterList[:, 1], xyzCenterList[:, 2])
        ax.scatter3D(xyzCenterMoving[0],
                     xyzCenterMoving[1], xyzCenterMoving[2])
        # line
        ax.plot3D([xyzCenter[0], xyzCenterMoving[0]], [xyzCenter[1],
                  xyzCenterMoving[1]], [xyzCenter[2], xyzCenterMoving[2]])
        plt.show()

    @staticmethod
    def CircleCoordinate(teta, r):
        '''
        circle coordination with teta and r

        args:
        teta: angle with x-axis
        r: circle radius
        '''
        x = r*np.cos(teta)
        y = r*np.sin(teta)
        return (x, y)

    @staticmethod
    def PeriodGenerator(n=100, w=1):
        '''
        set array of 2pi period
        '''
        recordsNo = w*n
        obsAnglesRes, obsAnglesStep = np.linspace(
            0, 2, recordsNo, retstep=True)
        obsAngles = obsAnglesRes*w*np.pi

        return obsAngles, obsAnglesStep

    @staticmethod
    def PeriodLimitGenerator(n=100, w=1, limits=[0, 0]):
        '''
        set array of 2pi period
        args:
            limits: list of min, max to be removed from the period
        '''
        # print(f"limits: {limits}")
        point1 = limits[0]
        point2 = limits[1]
        recordsNo = w*n
        obsAnglesRes, obsAnglesStep = np.linspace(
            point1, point2, recordsNo, retstep=True)
        obsAngles = obsAnglesRes

        return obsAngles, obsAnglesStep

    @staticmethod
    def SphericalToCartesianCoordinate(rtpPoint):
        '''
        convert spherical to cartesian points

        args:
            rtpPoint: r, teta, phi of spherical coordinate
        '''
        # spherical
        r = rtpPoint[0]
        teta = rtpPoint[1]
        phi = rtpPoint[2]
        # cartesian
        x = r*np.sin(phi)*np.cos(teta)
        y = r*np.sin(phi)*np.sin(teta)
        z = r*np.cos(phi)
        # res
        return np.array([x, y, z])

    @staticmethod
    def LineGenerator(n=100, w=1):
        recordsNo = w*n
        obsLengthRes, obsLengthStep = np.linspace(
            -10, 10, recordsNo, retstep=True)
        obsLength = obsLengthRes*w

        return obsLength, obsLengthStep

    @staticmethod
    def CartesianToSphericalCoordinate(xyzPoint):
        '''
        convert cartesian to spherical coordinate

        args:
            xyzPoint: x, y, z of cartesian coordinate
        '''
        # cartesian
        x = xyzPoint[0]
        y = xyzPoint[1]
        z = xyzPoint[2]
        # spherical
        r = np.sqrt(x**2 + y**2 + z**2)
        teta = np.arctan(y/x)
        # np.arccos(z/np.sqrt(x**2 + y**2 + z**2))
        phi = np.arctan(np.sqrt(x**2 + y**2)/z)
        # res
        return np.array([r, teta, phi]), np.array([r, np.degrees(teta), np.rad2deg(phi)])

    @staticmethod
    def create_formula(atom_elements):
        '''
        create mat using mat elements
        '''
        try:
            # check
            if len(atom_elements) == 0:
                raise Exception('atom elements list is empty')

            my_dict = {i: atom_elements.count(i) for i in atom_elements}
            # mat name
            elList = ''
            for key, value in my_dict.items():
                if value == 1:
                    _el = str(key)
                else:
                    _el = str(key)+str(value)
                elList += _el
                elList += ''
            # transform
            elList = elList.strip()

            return elList
        except Exception as e:
            raise

CartesianToSphericalCoordinate(xyzPoint) staticmethod

convert cartesian to spherical coordinate

Parameters:

Name Type Description Default
xyzPoint

x, y, z of cartesian coordinate

required
Source code in molvizr3d/docs/structure.py
@staticmethod
def CartesianToSphericalCoordinate(xyzPoint):
    '''
    convert cartesian to spherical coordinate

    args:
        xyzPoint: x, y, z of cartesian coordinate
    '''
    # cartesian
    x = xyzPoint[0]
    y = xyzPoint[1]
    z = xyzPoint[2]
    # spherical
    r = np.sqrt(x**2 + y**2 + z**2)
    teta = np.arctan(y/x)
    # np.arccos(z/np.sqrt(x**2 + y**2 + z**2))
    phi = np.arctan(np.sqrt(x**2 + y**2)/z)
    # res
    return np.array([r, teta, phi]), np.array([r, np.degrees(teta), np.rad2deg(phi)])

CenterObject(xyzList, centerPoint) staticmethod

move an object to the center of the origin [0,0,0]

Source code in molvizr3d/docs/structure.py
@staticmethod
def CenterObject(xyzList, centerPoint):
    '''
    move an object to the center of the origin [0,0,0]
    '''
    originPoint = np.array([0, 0, 0])
    movingCoordinate = originPoint - centerPoint
    newCenterPoints = np.array(xyzList) + movingCoordinate

    return newCenterPoints, movingCoordinate

CenterPoints(xyzList) staticmethod

find the center coordination of an object

Source code in molvizr3d/docs/structure.py
@staticmethod
def CenterPoints(xyzList):
    '''
    find the center coordination of an object
    '''
    # set
    xyzList = np.array(xyzList)
    # find the highest xyz
    # x
    xMax = np.max(xyzList[:, 0])
    xMin = np.min(xyzList[:, 0])
    if np.abs(xMax) != np.abs(xMin):
        xLen = np.abs(xMax - xMin)
        xCenter = xMin + (xLen/2)
    else:
        xLen = 0
        xCenter = 0 + (xLen/2)
    # print(f"X value: {xMin}, {xMax}")

    # y
    yMax = np.max(xyzList[:, 1])
    yMin = np.min(xyzList[:, 1])
    if np.abs(yMax) != np.abs(yMin):
        yLen = np.abs(yMax - yMin)
        yCenter = yMin + (yLen/2)
    else:
        yLen = 0
        yCenter = 0 + (yLen/2)
    # print(f"Y value: {yMin}, {yMax}")

    # z
    zMax = np.max(xyzList[:, 2])
    zMin = np.min(xyzList[:, 2])
    if np.abs(zMax) != np.abs(zMin):
        zLen = np.abs(zMax - zMin)
        zCenter = zMin + (zLen/2)
    else:
        zLen = 0
        zCenter = 0 + (zLen/2)
    # print(f"Z value: {zMin}, {zMax}")

    # object base
    objectBaseCoordinate = np.array([xCenter, yCenter, zCenter])

    return objectBaseCoordinate

CircleCoordinate(teta, r) staticmethod

circle coordination with teta and r

args: teta: angle with x-axis r: circle radius

Source code in molvizr3d/docs/structure.py
@staticmethod
def CircleCoordinate(teta, r):
    '''
    circle coordination with teta and r

    args:
    teta: angle with x-axis
    r: circle radius
    '''
    x = r*np.cos(teta)
    y = r*np.sin(teta)
    return (x, y)

ObjectDislay(xyzList, xyzCenterList) staticmethod

display object in two places

Source code in molvizr3d/docs/structure.py
@staticmethod
def ObjectDislay(xyzList, xyzCenterList):
    '''
    display object in two places
    '''
    # find the center of object
    xyzCenter = Structure.CenterPoints(xyzList)
    # find the center of object after moving to the origin [0,0,0]
    xyzCenterMoving = Structure.CenterPoints(xyzCenterList)

    # 3d plot
    fig = plt.figure()
    ax = plt.axes(projection='3d')
    ax.scatter3D(xyzList[:, 0], xyzList[:, 1], xyzList[:, 2])
    ax.scatter3D(xyzCenter[0], xyzCenter[1], xyzCenter[2])
    ax.scatter3D(xyzCenterList[:, 0],
                 xyzCenterList[:, 1], xyzCenterList[:, 2])
    ax.scatter3D(xyzCenterMoving[0],
                 xyzCenterMoving[1], xyzCenterMoving[2])
    # line
    ax.plot3D([xyzCenter[0], xyzCenterMoving[0]], [xyzCenter[1],
              xyzCenterMoving[1]], [xyzCenter[2], xyzCenterMoving[2]])
    plt.show()

PeriodGenerator(n=100, w=1) staticmethod

set array of 2pi period

Source code in molvizr3d/docs/structure.py
@staticmethod
def PeriodGenerator(n=100, w=1):
    '''
    set array of 2pi period
    '''
    recordsNo = w*n
    obsAnglesRes, obsAnglesStep = np.linspace(
        0, 2, recordsNo, retstep=True)
    obsAngles = obsAnglesRes*w*np.pi

    return obsAngles, obsAnglesStep

PeriodLimitGenerator(n=100, w=1, limits=[0, 0]) staticmethod

set array of 2pi period args: limits: list of min, max to be removed from the period

Source code in molvizr3d/docs/structure.py
@staticmethod
def PeriodLimitGenerator(n=100, w=1, limits=[0, 0]):
    '''
    set array of 2pi period
    args:
        limits: list of min, max to be removed from the period
    '''
    # print(f"limits: {limits}")
    point1 = limits[0]
    point2 = limits[1]
    recordsNo = w*n
    obsAnglesRes, obsAnglesStep = np.linspace(
        point1, point2, recordsNo, retstep=True)
    obsAngles = obsAnglesRes

    return obsAngles, obsAnglesStep

SphericalToCartesianCoordinate(rtpPoint) staticmethod

convert spherical to cartesian points

Parameters:

Name Type Description Default
rtpPoint

r, teta, phi of spherical coordinate

required
Source code in molvizr3d/docs/structure.py
@staticmethod
def SphericalToCartesianCoordinate(rtpPoint):
    '''
    convert spherical to cartesian points

    args:
        rtpPoint: r, teta, phi of spherical coordinate
    '''
    # spherical
    r = rtpPoint[0]
    teta = rtpPoint[1]
    phi = rtpPoint[2]
    # cartesian
    x = r*np.sin(phi)*np.cos(teta)
    y = r*np.sin(phi)*np.sin(teta)
    z = r*np.cos(phi)
    # res
    return np.array([x, y, z])

create_formula(atom_elements) staticmethod

create mat using mat elements

Source code in molvizr3d/docs/structure.py
@staticmethod
def create_formula(atom_elements):
    '''
    create mat using mat elements
    '''
    try:
        # check
        if len(atom_elements) == 0:
            raise Exception('atom elements list is empty')

        my_dict = {i: atom_elements.count(i) for i in atom_elements}
        # mat name
        elList = ''
        for key, value in my_dict.items():
            if value == 1:
                _el = str(key)
            else:
                _el = str(key)+str(value)
            elList += _el
            elList += ''
        # transform
        elList = elList.strip()

        return elList
    except Exception as e:
        raise

utility

Utility

Source code in molvizr3d/docs/utility.py
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
class Utility():

    json_csv_columns = [
        'file_name',
        'image_name_1',
        'image_name_2',
        'image_name_3',
        'mat_structure',
        'atom_numbers',
        'mat_cid',
        'mat_name',
        'mat_formula',
        'mat_smiles',
        'mat_mass',
        'atom_elements',
        'atom_atomic_number',
        'bond_numbers',
        'bond_list',
        'xyz_list',
        'xyz_center_list',
        'atom_weights',
        'mat_inchikey'
    ]

    def __init__(self):
        pass

    @staticmethod
    def CheckFileFormat(filePath):
        '''
        check file format

        args:
            filePath: file name dir

        return:
            file directory, file name, file format
        '''
        # check file exist
        if os.path.isfile(filePath):
            # file analysis
            fileDir = os.path.dirname(filePath)
            fileName = os.path.basename(filePath)
            fileFormat = os.path.splitext(filePath)[1]
            fileFormat = str(fileFormat.split(".")[-1]).lower()
            # res
            return fileDir, fileName, fileFormat
        else:
            raise Exception('file path is not valid.')

    @staticmethod
    def ReadContent(sourceContent):
        '''
        Read (load) file with respect to its format extension

        Parameters
        ----------
        sourceContent : dict
            contentFile: string content of a text file (url request)
            contentFormat: content format (sdf, json, ...)

        Returns
        -------
        file content : str
            content of a text file
        _contentFormat : str
            content format
        '''
        try:
            #
            _contentSource, _contentFormat = sourceContent.values()
            # check
            if _contentSource and _contentFormat:
                # read file
                if _contentFormat == 'sdf':
                    # string
                    fileContent = _contentSource
                elif _contentFormat == 'json':
                    # json convert to dict
                    fileContent = json.loads(_contentSource)
                elif _contentFormat == 'json-string':
                    # json convert to dict
                    fileContent = json.loads(_contentSource)

                # res
                return fileContent, _contentFormat
            else:
                raise Exception("target path is not valid.")
        except Exception as e:
            raise Exception(e)

    @staticmethod
    def OpenFile(filePath):
        '''
        Open file with respect to its format extension

        Parameters
        ----------
        filePath : str
            file path

        Returns
        -------
        file content : str
            content of a text file
        fileDir : str
            file directory
        fileName : str
            file name
        fileFormat : str
            file format
        '''
        try:
            # check
            if os.path.exists(filePath):
                # file info
                fileDir, fileName, fileFormat = Utility.CheckFileFormat(
                    filePath)

                # read a file
                with open(filePath, 'r') as f:
                    if fileFormat == 'sdf':
                        fileContent = f.read()
                    elif fileFormat == 'json':
                        fileContent = json.load(f)

                # res
                return fileContent, fileDir, fileName, fileFormat
            else:
                raise Exception("target path is not valid.")

        except Exception as e:
            raise Exception(e)

    @staticmethod
    def ListFiles(targetPath, fileExtension=''):
        '''
        list files in a target file

        Parameters
        ----------
        targetPath : str
            target path
        fileExtension : str
            file extension, default is empty

        Returns
        -------
        filesFound : list
            list of files in the target path
        '''
        try:
            # check
            if os.path.exists(targetPath):
                if not fileExtension:
                    # files
                    filesFound = os.listdir(targetPath)
                else:
                    # res
                    filesFound = []
                    for f in os.listdir(targetPath):
                        if f.endswith('.'+str(fileExtension).strip()):
                            filesFound.append(f)
                # res
                return filesFound
            else:
                raise Exception("target path is not valid.")

        except Exception as e:
            raise Exception(e)

    @staticmethod
    def SaveFile(fileContent, fileName, fileFormat, fileDir, logMessage=' file is successfully created and saved in'):
        '''
        save a file with respect to a format

        Parameters
        ----------
        fileContent : str
            file content
        fileName : str
            file name
        fileFormat : str
            file format
        fileDir : str
            file directory
        logMessage : str
            log message

        Returns
        -------
        bool
            True if the file is successfully created and saved in
        '''
        try:
            # set
            _fileFormat = str(fileFormat).lower()
            # file full name with format
            _fileFullName = fileName + f'.{_fileFormat}'
            # file full location
            fileLoc = os.path.join(fileDir, _fileFullName)

            # check
            if not os.path.isdir(fileDir):
                raise Exception('file directory is not valid.')

            # open file
            with open(fileLoc, 'w') as f:
                # check
                if _fileFormat == 'sdf':
                    # save
                    f.write(fileContent)
                    f.close()
                # FIXME
                if _fileFormat == 'json-string':
                    # save
                    json.dumps(fileContent, f, indent=5)
                    f.close()
                if _fileFormat == 'json':
                    # save ()
                    json.dump(fileContent, f, indent=5)
                    f.close()

            # log
            print(f"the {_fileFormat + logMessage} `{fileLoc}`")

            return True
        except Exception as e:
            raise Exception(e)

    @staticmethod
    def FindTargetFileInFolder(file_location, file_format):
        '''
        Find target files with respect to a specific format such as json

        Parameters
        ----------
        file_location : str
            file location
        file_format : str
            file format

        Returns
        -------
        listFiles : list
            list of target files
        '''
        try:
            # access directory
            allFiles = os.listdir(file_location)
            # file format
            fileExtension = f"*.{file_format}"
            # list
            listFiles = fnmatch.filter(allFiles, fileExtension)
            # res
            return listFiles
        except Exception as e:
            raise Exception(e)

    def SelectFile(list_file_names, file_name_ids, file_name_prefix='cid'):
        '''
        select files from a file list based on a query

        Parameters
        ----------
        list_file_names : list
            list of file names
        file_name_ids : list
            list of file ids
        file_name_prefix : str
            file name prefix

        Returns
        -------
        listFiles : list
            list of selected files
        '''
        try:
            # res
            listFiles = []
            cids = []

            # check
            if file_name_prefix == 'cid':
                # *** load only specific cids ***
                if len(file_name_ids) > 0 and len(list_file_names) > 0:
                    #
                    for i in range(len(list_file_names)):
                        _res = re.search(
                            r'(^cid_([0-9]+)(\.)([a-z0-9]*))', str(list_file_names[i]))
                        # check
                        if _res:
                            # save
                            _cid = _res.group(2)
                            cids.append(_cid)
                            # check
                            if _cid in file_name_ids:
                                _fileName = _res.group(1)
                                # save
                                listFiles.append(_fileName)
            elif file_name_prefix == 'file_name':
                # *** load only specific names ***
                if len(file_name_ids) > 0 and len(list_file_names) > 0:
                    #
                    _fileNames = [
                        item for item in file_name_ids if item in list_file_names]
                    # save
                    listFiles.extend(_fileName)
            # res
            return listFiles

        except Exception as e:
            raise Exception(e)

    @staticmethod
    def CreateCVS(csv_list, file_location, file_name='', file_format='json', save_location=''):
        '''
        Create csv file from dictionary

        Parameters
        ----------
        csv_list : list
            list of dictionary
        file_location : str
            file location
        file_name : str
            file name
        file_format : str
            file format
        save_location : str
            save location

        Returns
        -------
        _save_location : str
            save location
        csvFileName : str
            csv file name
        '''
        try:
            # check
            if len(save_location) == 0:
                _save_location = file_location
            else:
                _save_location = save_location

            # log
            _log = f"csv file is successfully created in {_save_location}"

            # csv file
            csvFileId = str(date.today()) + \
                "-" + str(random.randint(0, 256))

            # # file name
            if len(file_name) > 0:
                csvFileName = f'{file_name}.csv'
            else:
                csvFileName = f'cid_{csvFileId}.csv'

            # create path
            csvFile = os.path.join(_save_location, csvFileName)

            # write
            with open(csvFile, 'w') as f:
                writer = csv.DictWriter(
                    f, fieldnames=Utility.json_csv_columns)
                writer.writeheader()
                writer.writerows(csv_list)
                # log
                # print(_log)

            # res
            return _save_location, csvFileName
        except Exception as e:
            raise

    def ConvertCSVContentToList(csv_content):
        '''
        convert csv content (string) to list

        Parameters
        ----------
        csv_content : str
            csv string content

        Returns
        -------
        list
            list of csv content

        hint:
            list[0]: column head
            list[1]: records

        '''
        try:
            # csv column
            csv_column = []
            csv_rows = []

            #  csv list
            csv_list = csv_content.splitlines()
            # check
            if type(csv_list) is list:
                # len
                csv_list_len = len(csv_list)
                # csv column
                _column = str(csv_list[0]).replace(
                    "'", "").replace('"', '').split(',')
                csv_column.extend(_column)
                # csv rows
                _rows = str(csv_list[1]).replace(
                    "'", "").replace('"', '').split(',')
                csv_rows.extend(_rows)
            else:
                csv_list_len = -1

            # res
            return csv_list, csv_column, csv_rows, csv_list_len

        except Exception as e:
            raise Exception(e)

    @staticmethod
    def SaveNpArray(arr, file_name='', location=''):
        '''
        Save numpy array

        Parameters
        ----------
        arr : numpy array
            numpy array
        file_name : str
            file name
        location : str
            location

        '''
        try:
            # full file name
            if not file_name:
                file_name = "np_array"
            fullFileName = f"{file_name}.npy"
            # location
            fileLoc = os.path.join(location, fullFileName)

            # open
            with open(fileLoc, 'wb') as f:
                np.save(f, arr)

            print(f"save operation is done.")
        except Exception as e:
            raise Exception(e)

CheckFileFormat(filePath) staticmethod

check file format

Parameters:

Name Type Description Default
filePath

file name dir

required
return

file directory, file name, file format

Source code in molvizr3d/docs/utility.py
@staticmethod
def CheckFileFormat(filePath):
    '''
    check file format

    args:
        filePath: file name dir

    return:
        file directory, file name, file format
    '''
    # check file exist
    if os.path.isfile(filePath):
        # file analysis
        fileDir = os.path.dirname(filePath)
        fileName = os.path.basename(filePath)
        fileFormat = os.path.splitext(filePath)[1]
        fileFormat = str(fileFormat.split(".")[-1]).lower()
        # res
        return fileDir, fileName, fileFormat
    else:
        raise Exception('file path is not valid.')

ConvertCSVContentToList(csv_content)

convert csv content (string) to list

Parameters

csv_content : str csv string content

Returns

list list of csv content

hint

list[0]: column head list[1]: records

Source code in molvizr3d/docs/utility.py
def ConvertCSVContentToList(csv_content):
    '''
    convert csv content (string) to list

    Parameters
    ----------
    csv_content : str
        csv string content

    Returns
    -------
    list
        list of csv content

    hint:
        list[0]: column head
        list[1]: records

    '''
    try:
        # csv column
        csv_column = []
        csv_rows = []

        #  csv list
        csv_list = csv_content.splitlines()
        # check
        if type(csv_list) is list:
            # len
            csv_list_len = len(csv_list)
            # csv column
            _column = str(csv_list[0]).replace(
                "'", "").replace('"', '').split(',')
            csv_column.extend(_column)
            # csv rows
            _rows = str(csv_list[1]).replace(
                "'", "").replace('"', '').split(',')
            csv_rows.extend(_rows)
        else:
            csv_list_len = -1

        # res
        return csv_list, csv_column, csv_rows, csv_list_len

    except Exception as e:
        raise Exception(e)

CreateCVS(csv_list, file_location, file_name='', file_format='json', save_location='') staticmethod

Create csv file from dictionary

Parameters

csv_list : list list of dictionary file_location : str file location file_name : str file name file_format : str file format save_location : str save location

Returns

_save_location : str save location csvFileName : str csv file name

Source code in molvizr3d/docs/utility.py
@staticmethod
def CreateCVS(csv_list, file_location, file_name='', file_format='json', save_location=''):
    '''
    Create csv file from dictionary

    Parameters
    ----------
    csv_list : list
        list of dictionary
    file_location : str
        file location
    file_name : str
        file name
    file_format : str
        file format
    save_location : str
        save location

    Returns
    -------
    _save_location : str
        save location
    csvFileName : str
        csv file name
    '''
    try:
        # check
        if len(save_location) == 0:
            _save_location = file_location
        else:
            _save_location = save_location

        # log
        _log = f"csv file is successfully created in {_save_location}"

        # csv file
        csvFileId = str(date.today()) + \
            "-" + str(random.randint(0, 256))

        # # file name
        if len(file_name) > 0:
            csvFileName = f'{file_name}.csv'
        else:
            csvFileName = f'cid_{csvFileId}.csv'

        # create path
        csvFile = os.path.join(_save_location, csvFileName)

        # write
        with open(csvFile, 'w') as f:
            writer = csv.DictWriter(
                f, fieldnames=Utility.json_csv_columns)
            writer.writeheader()
            writer.writerows(csv_list)
            # log
            # print(_log)

        # res
        return _save_location, csvFileName
    except Exception as e:
        raise

FindTargetFileInFolder(file_location, file_format) staticmethod

Find target files with respect to a specific format such as json

Parameters

file_location : str file location file_format : str file format

Returns

listFiles : list list of target files

Source code in molvizr3d/docs/utility.py
@staticmethod
def FindTargetFileInFolder(file_location, file_format):
    '''
    Find target files with respect to a specific format such as json

    Parameters
    ----------
    file_location : str
        file location
    file_format : str
        file format

    Returns
    -------
    listFiles : list
        list of target files
    '''
    try:
        # access directory
        allFiles = os.listdir(file_location)
        # file format
        fileExtension = f"*.{file_format}"
        # list
        listFiles = fnmatch.filter(allFiles, fileExtension)
        # res
        return listFiles
    except Exception as e:
        raise Exception(e)

ListFiles(targetPath, fileExtension='') staticmethod

list files in a target file

Parameters

targetPath : str target path fileExtension : str file extension, default is empty

Returns

filesFound : list list of files in the target path

Source code in molvizr3d/docs/utility.py
@staticmethod
def ListFiles(targetPath, fileExtension=''):
    '''
    list files in a target file

    Parameters
    ----------
    targetPath : str
        target path
    fileExtension : str
        file extension, default is empty

    Returns
    -------
    filesFound : list
        list of files in the target path
    '''
    try:
        # check
        if os.path.exists(targetPath):
            if not fileExtension:
                # files
                filesFound = os.listdir(targetPath)
            else:
                # res
                filesFound = []
                for f in os.listdir(targetPath):
                    if f.endswith('.'+str(fileExtension).strip()):
                        filesFound.append(f)
            # res
            return filesFound
        else:
            raise Exception("target path is not valid.")

    except Exception as e:
        raise Exception(e)

OpenFile(filePath) staticmethod

Open file with respect to its format extension

Parameters

filePath : str file path

Returns

file content : str content of a text file fileDir : str file directory fileName : str file name fileFormat : str file format

Source code in molvizr3d/docs/utility.py
@staticmethod
def OpenFile(filePath):
    '''
    Open file with respect to its format extension

    Parameters
    ----------
    filePath : str
        file path

    Returns
    -------
    file content : str
        content of a text file
    fileDir : str
        file directory
    fileName : str
        file name
    fileFormat : str
        file format
    '''
    try:
        # check
        if os.path.exists(filePath):
            # file info
            fileDir, fileName, fileFormat = Utility.CheckFileFormat(
                filePath)

            # read a file
            with open(filePath, 'r') as f:
                if fileFormat == 'sdf':
                    fileContent = f.read()
                elif fileFormat == 'json':
                    fileContent = json.load(f)

            # res
            return fileContent, fileDir, fileName, fileFormat
        else:
            raise Exception("target path is not valid.")

    except Exception as e:
        raise Exception(e)

ReadContent(sourceContent) staticmethod

Read (load) file with respect to its format extension

Parameters

sourceContent : dict contentFile: string content of a text file (url request) contentFormat: content format (sdf, json, ...)

Returns

file content : str content of a text file _contentFormat : str content format

Source code in molvizr3d/docs/utility.py
@staticmethod
def ReadContent(sourceContent):
    '''
    Read (load) file with respect to its format extension

    Parameters
    ----------
    sourceContent : dict
        contentFile: string content of a text file (url request)
        contentFormat: content format (sdf, json, ...)

    Returns
    -------
    file content : str
        content of a text file
    _contentFormat : str
        content format
    '''
    try:
        #
        _contentSource, _contentFormat = sourceContent.values()
        # check
        if _contentSource and _contentFormat:
            # read file
            if _contentFormat == 'sdf':
                # string
                fileContent = _contentSource
            elif _contentFormat == 'json':
                # json convert to dict
                fileContent = json.loads(_contentSource)
            elif _contentFormat == 'json-string':
                # json convert to dict
                fileContent = json.loads(_contentSource)

            # res
            return fileContent, _contentFormat
        else:
            raise Exception("target path is not valid.")
    except Exception as e:
        raise Exception(e)

SaveFile(fileContent, fileName, fileFormat, fileDir, logMessage=' file is successfully created and saved in') staticmethod

save a file with respect to a format

Parameters

fileContent : str file content fileName : str file name fileFormat : str file format fileDir : str file directory logMessage : str log message

Returns

bool True if the file is successfully created and saved in

Source code in molvizr3d/docs/utility.py
@staticmethod
def SaveFile(fileContent, fileName, fileFormat, fileDir, logMessage=' file is successfully created and saved in'):
    '''
    save a file with respect to a format

    Parameters
    ----------
    fileContent : str
        file content
    fileName : str
        file name
    fileFormat : str
        file format
    fileDir : str
        file directory
    logMessage : str
        log message

    Returns
    -------
    bool
        True if the file is successfully created and saved in
    '''
    try:
        # set
        _fileFormat = str(fileFormat).lower()
        # file full name with format
        _fileFullName = fileName + f'.{_fileFormat}'
        # file full location
        fileLoc = os.path.join(fileDir, _fileFullName)

        # check
        if not os.path.isdir(fileDir):
            raise Exception('file directory is not valid.')

        # open file
        with open(fileLoc, 'w') as f:
            # check
            if _fileFormat == 'sdf':
                # save
                f.write(fileContent)
                f.close()
            # FIXME
            if _fileFormat == 'json-string':
                # save
                json.dumps(fileContent, f, indent=5)
                f.close()
            if _fileFormat == 'json':
                # save ()
                json.dump(fileContent, f, indent=5)
                f.close()

        # log
        print(f"the {_fileFormat + logMessage} `{fileLoc}`")

        return True
    except Exception as e:
        raise Exception(e)

SaveNpArray(arr, file_name='', location='') staticmethod

Save numpy array

Parameters

arr : numpy array numpy array file_name : str file name location : str location

Source code in molvizr3d/docs/utility.py
@staticmethod
def SaveNpArray(arr, file_name='', location=''):
    '''
    Save numpy array

    Parameters
    ----------
    arr : numpy array
        numpy array
    file_name : str
        file name
    location : str
        location

    '''
    try:
        # full file name
        if not file_name:
            file_name = "np_array"
        fullFileName = f"{file_name}.npy"
        # location
        fileLoc = os.path.join(location, fullFileName)

        # open
        with open(fileLoc, 'wb') as f:
            np.save(f, arr)

        print(f"save operation is done.")
    except Exception as e:
        raise Exception(e)

SelectFile(list_file_names, file_name_ids, file_name_prefix='cid')

select files from a file list based on a query

Parameters

list_file_names : list list of file names file_name_ids : list list of file ids file_name_prefix : str file name prefix

Returns

listFiles : list list of selected files

Source code in molvizr3d/docs/utility.py
def SelectFile(list_file_names, file_name_ids, file_name_prefix='cid'):
    '''
    select files from a file list based on a query

    Parameters
    ----------
    list_file_names : list
        list of file names
    file_name_ids : list
        list of file ids
    file_name_prefix : str
        file name prefix

    Returns
    -------
    listFiles : list
        list of selected files
    '''
    try:
        # res
        listFiles = []
        cids = []

        # check
        if file_name_prefix == 'cid':
            # *** load only specific cids ***
            if len(file_name_ids) > 0 and len(list_file_names) > 0:
                #
                for i in range(len(list_file_names)):
                    _res = re.search(
                        r'(^cid_([0-9]+)(\.)([a-z0-9]*))', str(list_file_names[i]))
                    # check
                    if _res:
                        # save
                        _cid = _res.group(2)
                        cids.append(_cid)
                        # check
                        if _cid in file_name_ids:
                            _fileName = _res.group(1)
                            # save
                            listFiles.append(_fileName)
        elif file_name_prefix == 'file_name':
            # *** load only specific names ***
            if len(file_name_ids) > 0 and len(list_file_names) > 0:
                #
                _fileNames = [
                    item for item in file_name_ids if item in list_file_names]
                # save
                listFiles.extend(_fileName)
        # res
        return listFiles

    except Exception as e:
        raise Exception(e)

vizr3d

Vizr3D

3D Visualizer of a compound

hint

xyzList is selected for visualization

Source code in molvizr3d/docs/vizr3d.py
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
class Vizr3D():
    '''
    3D Visualizer of a compound

    hint:
        xyzList is selected for visualization
    '''

    # properties
    _structure_type = ''
    plotScale = []

    def __init__(self, atomElements, atomBonds, xyzList, xyzCenterList, robs, tetaNo, phiNo, limits):
        self.atomElements = atomElements
        # bond block (info)
        self.atomBonds = atomBonds
        self.xyzList = xyzList
        self.xyzCenterList = xyzCenterList
        self.robs = robs
        self.tetaNo = tetaNo
        self.phiNo = phiNo
        self.limits = limits

        # set structure type
        structureType, perpendicularAxis, perpendicularVector, XYZ0 = self.StructureAnalyzer()
        self.structure_type = structureType

    @property
    def structure_type(self):
        return self._structure_type

    @structure_type.setter
    def structure_type(self, value):
        self._structure_type = value

    def StructureAnalyzer(self):
        '''
        Check geometry structure to determine 2D/3D

        Parameters
        ----------
        xyzList: list
            point coordination

        Returns
        -------
        structureType: str
            2D or 3D
        '''
        try:
            # array
            xyzList = np.array(self.xyzList)
            # set
            X = xyzList[:, 0]
            Y = xyzList[:, 1]
            Z = xyzList[:, 2]

            # check plane structure (2D, 3D)
            X0 = np.abs(X).sum()
            Y0 = np.abs(Y).sum()
            Z0 = np.abs(Z).sum()
            XYZ0 = [X0, Y0, Z0]

            # perpendicular vector [x,y,z]
            perpendicularVector = [False, False, False]
            # set
            if X0 == 0:
                perpendicularVector[0] = True

            if Y0 == 0:
                perpendicularVector[1] = True

            if Z0 == 0:
                perpendicularVector[2] = True

            # status
            if True in perpendicularVector:
                structureType = '2D'
            else:
                structureType = '3D'

            # axis selection
            perpendicularAxis = []
            if perpendicularVector[0] is True:
                perpendicularAxis.append('X')
            if perpendicularVector[1] is True:
                perpendicularAxis.append('Y')
            if perpendicularVector[2] is True:
                perpendicularAxis.append('Z')

            return structureType, perpendicularAxis, perpendicularVector, XYZ0
        except Exception as e:
            raise Exception(e)

    def set_color(self, atom_symbol):
        '''
        Set a color for each compound
        taken from https://en.wikipedia.org/wiki/CPK_coloring

        Parameters
        ----------
        atom_symbol: str
            atom symbol

        Returns
        -------
        color: str
            atom color
        '''
        colors = {
            "H": '#ffffff',
            "C": '#BCBCBC',
            "N": '#0586f6',
            "O": '#f6052a',
            "F": '#2dd930',
            "Cl": '#2dd930',
            "Br": '#950e0e',
            "I": '#360e89',
            "He": '#3dbaf1',
            "Ne": '#3dbaf1',
            "Ar": '#3dbaf1',
            "Kr": '#3dbaf1',
            "Xe": '#3dbaf1',
            "P": '#f1a03d',
            "S": '#f1ef3d',
            "B": '#efc867',
            "Li": '#6b3ccb',
            "Na": '#6b3ccb',
            "K": '#6b3ccb',
            "Rb": '#6b3ccb',
            "Cs": '#6b3ccb',
            "Fr": '#6b3ccb',
            "Be": '#1c881e',
            "Mg": '#1c881e',
            "Ca": '#1c881e',
            "Sr": '#1c881e',
            "Ba": '#1c881e',
            "Ra": '#1c881e',
            "Ti": '#3d3e40',
            "Fe": '#a48620',
            "other": '#a729ba'
        }

        # check
        _color = colors.get(str(atom_symbol))
        if _color is None:
            return colors.get(str('other'))
        else:
            return _color

    def set_size(self, symbol, _sy=300, _s=1):
        '''
        Set atom size (spherical shape)

        Parameters
        ----------
        symbol: str
            atom symbol
        _s: int
            size

        Returns
        -------
        size: int
            size
        '''
        _sy = 300
        _sx = 0.50*_sy

        sizes = {
            "H": _s*_sx,
            "C": _s*_sy,
            "N": _s*_sy,
            "O": _s*_sy,
            "F": _s*_sy,
            "Cl": _s*_sx,
            "Br": _s*_sy,
            "I": _s*_sy,
            "He": _s*_sy,
            "Ne": _s*_sy,
            "Ar": _s*_sy,
            "Kr": _s*_sy,
            "Xe": _s*_sy,
            "P": _s*_sy,
            "S": _s*_sy,
            "B": _s*_sy,
            "Li": _s*_sy,
            "Na": _s*_sy,
            "K": _s*_sy,
            "Rb": _s*_sy,
            "Cs": _s*_sy,
            "Fr": _s*_sy,
            "Be": _s*_sy,
            "Mg": _s*_sy,
            "Ca": _s*_sy,
            "Sr": _s*_sy,
            "Ba": _s*_sy,
            "Ra": _s*_sy,
            "Ti": _s*_sy,
            "Fe": _s*_sy,
            "other": _s*_sy,
        }

        _size = sizes.get(symbol)
        if _size is None:
            _sizeSet = int(sizes.get('other'))
        else:
            _sizeSet = int(_size)

        return _sizeSet

    def create_3dframe(self):
        '''
        Create 3d frame dimension
        '''
        # max length
        # x
        xMin = np.min(self.xyzList[:, 0])
        xMax = np.max(self.xyzList[:, 0])
        xLen = np.abs(np.abs(xMax) - np.abs(xMin))
        # y
        yMin = np.min(self.xyzList[:, 1])
        yMax = np.max(self.xyzList[:, 1])
        yLen = np.abs(np.abs(yMax) - np.abs(yMin))
        # z
        zMin = np.min(self.xyzList[:, 2])
        zMax = np.max(self.xyzList[:, 2])
        zLen = np.abs(np.abs(zMax) - np.abs(zMin))
        # max
        xyzLenMax = np.max([xMax, yMax, zMax])
        xyzLenMin = np.min([xMin, yMin, zMin])
        xyzR = 1/xyzLenMax

        # res
        return xyzLenMax, xyzLenMin, xyzR, xLen, yLen, zLen

    def create_bond_line(self, xyz1, xyz2, bond_type, xyzL=[1, 1, 1], xyzR=0.15):
        '''
        Create bond line (single, double, tipple)

        Parameters
        ----------
        xyz1: list
            (x,y,z) point 1
        xyz2: list
            (x,y,z) point 2
        bond_type: int
            bond type (1,2,3)
        xyzL: list
            (x,y,z) length
        xyzR: int
            (x,y,z) radius

        Returns
        -------
        bondLines: list
            list of bond lines
        '''
        # bond lines
        bondLines = []
        # bond length
        bondLength = []

        xL, yL, zL = xyzR*np.array(xyzL)

        # Calculate center-to-center vector
        center_vector = np.array(xyz2) - np.array(xyz1)

        # Calculate center-to-center line
        center_line = [[xyz1[0], xyz2[0]], [
            xyz1[1], xyz2[1]], [xyz1[2], xyz2[2]]]

        if bond_type == 1:
            # bond line
            bondLines.append(center_line)
            # bond length
            _bond_length_res = self.calculate_distance(xyz1, xyz2)
            bondLength.append(_bond_length_res)

        elif bond_type == 2:
            # parallel line
            # y increase
            # center to center line
            # Calculate perpendicular vector to center vector
            perp_vector = np.array([center_vector[1], - center_vector[0], 0])
            perp_vector /= np.linalg.norm(perp_vector)

            # Calculate offset vectors
            offset_vector1 = 0.15 * perp_vector
            offset_vector2 = -0.15 * perp_vector

            # Calculate parallel lines
            _l1 = [[xyz1[0]+offset_vector1[0], xyz2[0]+offset_vector1[0]], [
                xyz1[1]+offset_vector1[1], xyz2[1]+offset_vector1[1]], [xyz1[2]+offset_vector1[2], xyz2[2]+offset_vector1[2]]]
            _l2 = [[xyz1[0]+offset_vector2[0], xyz2[0]+offset_vector2[0]], [
                xyz1[1]+offset_vector2[1], xyz2[1]+offset_vector2[1]], [xyz1[2]+offset_vector2[2], xyz2[2]+offset_vector2[2]]]

            # lines
            _l1_xyz1 = [xyz1[0]+offset_vector1[0], xyz1[1] +
                        offset_vector1[1], xyz1[2]+offset_vector1[2]]
            _l1_xyz2 = [xyz2[0]+offset_vector1[0], xyz2[1] +
                        offset_vector1[1], xyz2[2]+offset_vector1[2]]

            _l2_xyz1 = [xyz1[0]+offset_vector2[0], xyz1[1] +
                        offset_vector2[1], xyz1[2]+offset_vector2[2]]
            _l2_xyz2 = [xyz2[0]+offset_vector2[0], xyz2[1] +
                        offset_vector2[1], xyz2[2]+offset_vector2[2]]

            # bond lines
            bondLines.append(_l1)
            bondLines.append(_l2)
            # bond length
            _bond_length_res = self.calculate_distance(_l1_xyz1, _l1_xyz2)
            bondLength.append(_bond_length_res)
            _bond_length_res = self.calculate_distance(_l2_xyz1, _l2_xyz2)
            bondLength.append(_bond_length_res)

        elif bond_type == 3:
            # parallel line
            # y increase
            # line
            # Calculate perpendicular vector to center vector
            perp_vector = np.array([center_vector[1], -center_vector[0], 0])
            perp_vector /= np.linalg.norm(perp_vector)

            # Calculate offset vectors
            offset_vector1 = 0.125 * perp_vector
            offset_vector2 = -0.125 * perp_vector

            # Calculate parallel lines
            _l1 = [[xyz1[0]+offset_vector1[0], xyz2[0]+offset_vector1[0]], [
                xyz1[1]+offset_vector1[1], xyz2[1]+offset_vector1[1]], [xyz1[2]+offset_vector1[2], xyz2[2]+offset_vector1[2]]]
            _l2 = [[xyz1[0], xyz2[0]], [
                xyz1[1], xyz2[1]], [xyz1[2], xyz2[2]]]

            _l3 = [[xyz1[0]+offset_vector2[0], xyz2[0]+offset_vector2[0]], [
                xyz1[1]+offset_vector2[1], xyz2[1]+offset_vector2[1]], [xyz1[2]+offset_vector2[2], xyz2[2]+offset_vector2[2]]]

            # lines
            _l1_xyz1 = [xyz1[0]+offset_vector1[0], xyz1[1] +
                        offset_vector1[1], xyz1[2]+offset_vector1[2]]
            _l1_xyz2 = [xyz2[0]+offset_vector1[0], xyz2[1] +
                        offset_vector1[1], xyz2[2]+offset_vector1[2]]
            _l2_xyz1 = xyz1
            _l2_xyz2 = xyz2
            _l3_xyz1 = [xyz1[0]+offset_vector2[0], xyz1[1] +
                        offset_vector2[1], xyz1[2]+offset_vector2[2]]
            _l3_xyz2 = [xyz2[0]+offset_vector2[0], xyz2[1] +
                        offset_vector2[1], xyz2[2]+offset_vector2[2]]

            # bond lines
            bondLines.append(_l1)
            bondLines.append(_l2)
            bondLines.append(_l3)
            # bond length
            # bond length
            _bond_length_res = self.calculate_distance(_l1_xyz1, _l1_xyz2)
            bondLength.append(_bond_length_res)
            _bond_length_res = self.calculate_distance(_l2_xyz1, _l2_xyz2)
            bondLength.append(_bond_length_res)
            _bond_length_res = self.calculate_distance(_l3_xyz1, _l3_xyz2)
            bondLength.append(_bond_length_res)

        return bondLines, bond_type, bondLength

    def create_bond_line_V2(self, xyz1, xyz2, bond_type, xyzL=[1, 1, 1], xyzR=0.15):
        '''
        Create bond line (single, double, triple)

        Parameters
        ----------
        xyz1: list
            (x,y,z) point 1
        xyz2: list
            (x,y,z) point 2
        bond_type: int
            bond type (1,2,3)
        xyzL: list
            (x,y,z) length
        xyzR: int
            (x,y,z) radius

        Returns
        -------
        bondLines: list
            list of bond lines
        '''
        bondLines = []

        xL, yL, zL = xyzR*np.array(xyzL)

        # Calculate center-to-center vector
        center_vector = np.array(xyz2) - np.array(xyz1)

        # Calculate center-to-center line
        center_line = [[xyz1[0], xyz2[0]], [
            xyz1[1], xyz2[1]], [xyz1[2], xyz2[2]]]

        # Calculate midpoint
        midpoint = [(xyz1[0] + xyz2[0]) / 2, (xyz1[1] +
                                              xyz2[1]) / 2, (xyz1[2] + xyz2[2]) / 2]

        if bond_type == 1:
            # Break single bond into two lines
            bondLines.append(
                [[xyz1[0], midpoint[0]], [xyz1[1], midpoint[1]], [xyz1[2], midpoint[2]]])
            bondLines.append(
                [[midpoint[0], xyz2[0]], [midpoint[1], xyz2[1]], [midpoint[2], xyz2[2]]])

        elif bond_type == 2:
            # parallel line
            # y increase
            # center to center line
            # Calculate perpendicular vector to center vector
            perp_vector = np.array([center_vector[1], - center_vector[0], 0])
            perp_vector /= np.linalg.norm(perp_vector)

            # Calculate offset vectors
            offset_vector1 = 0.15 * perp_vector
            offset_vector2 = -0.15 * perp_vector

            # Calculate parallel lines
            _l1 = [[xyz1[0]+offset_vector1[0], xyz2[0]+offset_vector1[0]], [
                xyz1[1]+offset_vector1[1], xyz2[1]+offset_vector1[1]], [xyz1[2]+offset_vector1[2], xyz2[2]+offset_vector1[2]]]
            _l2 = [[xyz1[0]+offset_vector2[0], xyz2[0]+offset_vector2[0]], [
                xyz1[1]+offset_vector2[1], xyz2[1]+offset_vector2[1]], [xyz1[2]+offset_vector2[2], xyz2[2]+offset_vector2[2]]]

            # Break each parallel line into two lines
            bondLines.append([[xyz1[0]+offset_vector1[0], midpoint[0]+offset_vector1[0]], [
                xyz1[1]+offset_vector1[1], midpoint[1]+offset_vector1[1]], [xyz1[2]+offset_vector1[2], midpoint[2]+offset_vector1[2]]])
            bondLines.append([[midpoint[0]+offset_vector1[0], xyz2[0]+offset_vector1[0]], [
                midpoint[1]+offset_vector1[1], xyz2[1]+offset_vector1[1]], [midpoint[2]+offset_vector1[2], xyz2[2]+offset_vector1[2]]])
            bondLines.append([[xyz1[0]+offset_vector2[0], midpoint[0]+offset_vector2[0]], [
                xyz1[1]+offset_vector2[1], midpoint[1]+offset_vector2[1]], [xyz1[2]+offset_vector2[2], midpoint[2]+offset_vector2[2]]])
            bondLines.append([[midpoint[0]+offset_vector2[0], xyz2[0]+offset_vector2[0]], [
                midpoint[1]+offset_vector2[1], xyz2[1]+offset_vector2[1]], [midpoint[2]+offset_vector2[2], xyz2[2]+offset_vector2[2]]])

        elif bond_type == 3:
            # parallel line
            # y increase
            # line
            # Calculate perpendicular vector to center vector
            perp_vector = np.array([center_vector[1], -center_vector[0], 0])
            perp_vector /= np.linalg.norm(perp_vector)

            # Calculate offset vectors
            offset_vector1 = 0.125 * perp_vector
            offset_vector2 = -0.125 * perp_vector

            # Calculate parallel lines
            _l1 = [[xyz1[0]+offset_vector1[0], xyz2[0]+offset_vector1[0]], [
                xyz1[1]+offset_vector1[1], xyz2[1]+offset_vector1[1]], [xyz1[2]+offset_vector1[2], xyz2[2]+offset_vector1[2]]]
            _l2 = [[xyz1[0], xyz2[0]], [
                xyz1[1], xyz2[1]], [xyz1[2], xyz2[2]]]
            _l3 = [[xyz1[0]+offset_vector2[0], xyz2[0]+offset_vector2[0]], [
                xyz1[1]+offset_vector2[1], xyz2[1]+offset_vector2[1]], [xyz1[2]+offset_vector2[2], xyz2[2]+offset_vector2[2]]]

            # Break each parallel line into two lines
            bondLines.append([[xyz1[0]+offset_vector1[0], midpoint[0]+offset_vector1[0]], [
                xyz1[1]+offset_vector1[1], midpoint[1]+offset_vector1[1]], [xyz1[2]+offset_vector1[2], midpoint[2]+offset_vector1[2]]])
            bondLines.append([[midpoint[0]+offset_vector1[0], xyz2[0]+offset_vector1[0]], [
                midpoint[1]+offset_vector1[1], xyz2[1]+offset_vector1[1]], [midpoint[2]+offset_vector1[2], xyz2[2]+offset_vector1[2]]])
            bondLines.append([[xyz1[0], midpoint[0]], [
                xyz1[1], midpoint[1]], [xyz1[2], midpoint[2]]])
            bondLines.append([[midpoint[0], xyz2[0]], [
                midpoint[1], xyz2[1]], [midpoint[2], xyz2[2]]])
            bondLines.append([[xyz1[0]+offset_vector2[0], midpoint[0]+offset_vector2[0]], [
                xyz1[1]+offset_vector2[1], midpoint[1]+offset_vector2[1]], [xyz1[2]+offset_vector2[2], midpoint[2]+offset_vector2[2]]])
            bondLines.append([[midpoint[0]+offset_vector2[0], xyz2[0]+offset_vector2[0]], [
                midpoint[1]+offset_vector2[1], xyz2[1]+offset_vector2[1]], [midpoint[2]+offset_vector2[2], xyz2[2]+offset_vector2[2]]])

        return bondLines, bond_type

    def line_mid_points(self, xyz1, xyz2):
        '''
        Divide a line in two equal parts

        Parameters
        ----------
        xyz1: list
            (x,y,z) point 1
        xyz2: list
            (x,y,z) point 2

        Returns
        -------
        midPoints: list
            list of mid points
        '''
        # Calculate midpoints
        midpoint_x = (xyz1[0] + xyz2[0]) / 2
        midpoint_y = (xyz1[1] + xyz2[1]) / 2
        midpoint_z = (xyz1[2] + xyz2[2]) / 2

        # Divide center_line into two parts
        part1 = [[xyz1[0], midpoint_x], [
            xyz1[1], midpoint_y], [xyz1[2], midpoint_z]]
        part2 = [[midpoint_x, xyz2[0]], [
            midpoint_y, xyz2[1]], [midpoint_z, xyz2[2]]]

        # Get four points
        point1 = [xyz1[0], xyz1[1], xyz1[2]]
        point2 = [midpoint_x, midpoint_y, midpoint_z]
        point3 = [midpoint_x, midpoint_y, midpoint_z]
        point4 = [xyz2[0], xyz2[1], xyz2[2]]

        # res
        return point1, point2, point3, point4, part1, part2

    def line_property(self, xyz1, xyz2):
        '''
        Check a line property with which plane is parallel
        when res contains two True, it means the False coordination contains all elements.

        Parameters
        ----------
        xyz1: list
            (x,y,z) point 1
        xyz2: list
            (x,y,z) point 2

        Returns
        -------
        res: bool
            res
        '''
        try:
            # mean value
            Xm = np.mean([xyz1[0], xyz2[0]])
            Ym = np.mean([xyz1[1], xyz2[1]])
            Zm = np.mean([xyz1[2], xyz2[2]])
            xyzMean = [Xm, Ym, Zm]

            # check plane
            isSubtractZero = np.array([False, False, False])

            # points in one line
            X = xyz1[0] - xyz2[0]
            Y = xyz1[1] - xyz2[1]
            Z = xyz1[2] - xyz2[2]
            xyzPlane = [X, Y, Z]

            # axis vector
            xyzL = np.array([0, 0, 0])

            # set
            # axis selection
            perpendicularAxis = np.array([False, False, False])
            if X == 0:
                isSubtractZero[0] = True
                perpendicularAxis[0] = True
                # xyzL = xyzL + np.array(1, 1, 0)

            if Y == 0:
                isSubtractZero[1] = True
                perpendicularAxis[1] = True
                # xyzL = xyzL + np.array(1, 1, 0)

            if Z == 0:
                isSubtractZero[2] = True
                perpendicularAxis[2] = True
                # xyzL = xyzL + np.array(1, 0, 1)

            # set xyzL
            xyzL = isSubtractZero.astype(int)

            return xyzMean, xyzPlane, isSubtractZero, xyzL, perpendicularAxis

        except Exception as e:
            raise Exception(e)

    def set_plot_scale(self):
        '''
        Set plot scale
        '''
        # atom no
        atomNo = len(self.xyzList)
        # bond no
        bondNo = len(self.atomBonds)

        # bond length list
        bondLengthList = []

        # *** using bond block
        for i in range(bondNo):
            # atom id
            _atom1Id = int(self.atomBonds[i]['id']) - 1
            # atom symbol
            _atom1Symbol = self.atomBonds[i]['symbol']
            # atom color
            _atom1Color = self.set_color(_atom1Symbol)
            # atom bond list
            _atom1BondList = self.atomBonds[i]['bonds']
            atom1BondSize = len(_atom1BondList)

            _atom1X = self.xyzList[_atom1Id, 0]
            _atom1Y = self.xyzList[_atom1Id, 1]
            _atom1Z = self.xyzList[_atom1Id, 2]
            _atom1XYZ = [_atom1X, _atom1Y, _atom1Z]

            # draw bond
            if atom1BondSize > 0:
                for j in range(atom1BondSize):
                    # atom [2] id
                    _atom2Id = int(_atom1BondList[j][0]) - 1
                    # atom [2] symbol
                    _atom2Symbol = _atom1BondList[j][1]
                    # atom color
                    _atom2Color = self.set_color(_atom2Symbol)
                    # atom [1] - atom [2] bond type
                    _bondType = int(_atom1BondList[j][3])

                    # xyz
                    _atom2X = self.xyzList[_atom2Id, 0]
                    _atom2Y = self.xyzList[_atom2Id, 1]
                    _atom2Z = self.xyzList[_atom2Id, 2]
                    _atom2XYZ = [_atom2X, _atom2Y, _atom2Z]

                    # bond connection (points)
                    _bondConnection, _bondTypeLog, _bondLengths = self.create_bond_line(
                        _atom1XYZ, _atom2XYZ, _bondType)

                    # save bond length
                    bondLengthList.append(_bondLengths)

        # check bond length list
        if len(bondLengthList) > 0:
            # flatten list
            bondLengthList_flatten = sum(bondLengthList, [])

            # max bond length
            maxBondLength = max(bondLengthList_flatten)
            # min bond length
            minBondLength = min(bondLengthList_flatten)
            # mean bond length
            meanBondLength = np.mean(bondLengthList_flatten)
            # median bond length
            medianBondLength = np.median(bondLengthList_flatten)

            # set plot scale
            self.plotScale = [minBondLength, maxBondLength,
                              meanBondLength, medianBondLength]

    def view3d(self, elev=None, azim=None, figSize='default', obsOption=[False, 0],
               dpi=100, pixel_width=800, pixel_height=600, bg_color='#090A0B', display_legend=True):
        '''
        Draw a compound in the cartesian coordinate
        atomElements atom symbol
        atomBonds atom bonds (bond blocks)
        xyzList atom position in the cartesian coordinate
        figSize=(10, 10) plt 3d setting
        obsOption=[False, 0] display center point [0,0,0]

        Parameters
        ----------
        elev: int
            elevation of the view angle (default: 30)
        azim: int
            azimuthal angle of the view angle (default: 30)
        figSize: tuple
            figure size
        obsOption: list
            display center point [False,0]
        dpi: int
            dots per inch
        pixel_width: int
            width of the figure in pixels
        pixel_height: int
            height of the figure in pixels
        bg_color: str
            background color
        display_legend: bool
            display legend

        Returns
        -------
        fig: figure
            figure
        '''
        # plot summary
        plot_summary = []
        # 3d plot
        if figSize == 'default':
            fig = plt.figure(figsize=(6, 6), facecolor=f'{bg_color}')
        else:
            fig_size_inches = (pixel_width / dpi, pixel_height / dpi)
            fig = plt.figure(figsize=fig_size_inches,
                             dpi=dpi, facecolor=f'{bg_color}')

        # remove paddings
        fig.tight_layout(pad=0)

        # projection
        ax = plt.axes(projection='3d')

        # Adjust the layout to fill the entire figure
        fig.subplots_adjust(left=0, right=1, top=1, bottom=0)

        # axis display
        plt.axis('off')
        # color
        ax_color = f'{bg_color}'
        ax.set_facecolor(ax_color)

        # legend
        legend_list = []

        # marker label
        marker_labels = []

        # atom no
        atomNo = len(self.xyzList)
        # bond no
        bondNo = len(self.atomBonds)

        # create 3d frame
        xyzLenMax, xyzLenMin, xyzR, xLen, yLen, zLen = self.create_3dframe()

        # *** plot scale
        plot_scale_res = self.set_plot_scale()
        # min bond length
        min_bond_length = self.plotScale[0]
        # max bond length
        max_bond_length = self.plotScale[1]
        # set marker size
        marker_size_0 = self.set_marker_size(min_bond_length, max_bond_length)

        # *** atom visualization
        for i in range(atomNo):
            # xyz
            _atom1X = self.xyzList[i, 0]
            _atom1Y = self.xyzList[i, 1]
            _atom1Z = self.xyzList[i, 2]
            _atom1XYZ = [_atom1X, _atom1Y, _atom1Z]

            # color
            # atom id
            _atomId = int(i+1)
            # symbol
            _atomSymbol = str(self.atomElements[i]).strip()
            # size
            _atomSize = self.set_size(_atomSymbol, _sy=marker_size_0)
            # color
            _atomColor = self.set_color(_atomSymbol)

            # atom mark
            atomMark = str(_atomSymbol) + str(_atomId)

            # atom label
            marker_labels.append(atomMark)

            # marker edgecolor
            marker_edgecolor = str('#5C5C5C')

            # legend list
            if _atomSymbol not in legend_list:
                legend_list.append(_atomSymbol)

                # draw atom 1
                ax.scatter3D(_atom1X, _atom1Y, _atom1Z,
                             label=_atomSymbol, s=_atomSize, color=_atomColor, edgecolors=marker_edgecolor)
            else:
                # draw atom 1
                ax.scatter3D(_atom1X, _atom1Y, _atom1Z,
                             s=_atomSize, color=_atomColor, edgecolors=marker_edgecolor)

        # *** atom label display
        # for i, label in enumerate(marker_labels):
        #     # xyz
        #     _atom1X = self.xyzList[i, 0]
        #     _atom1Y = self.xyzList[i, 1]
        #     _atom1Z = self.xyzList[i, 2]
        #     # set
        #     ax.text(_atom1X, _atom1Y, _atom1Z, label, ha='left',
        #             va='center', color='red', fontsize=12)

        # reset
        i = 0

        # *** bond visualization
        # *** using bond block
        for i in range(bondNo):
            # atom id
            _atom1Id = int(self.atomBonds[i]['id']) - 1
            # atom symbol
            _atom1Symbol = self.atomBonds[i]['symbol']
            # atom color
            _atom1Color = self.set_color(_atom1Symbol)
            # atom bond list
            _atom1BondList = self.atomBonds[i]['bonds']
            atom1BondSize = len(_atom1BondList)

            _atom1X = self.xyzList[_atom1Id, 0]
            _atom1Y = self.xyzList[_atom1Id, 1]
            _atom1Z = self.xyzList[_atom1Id, 2]
            _atom1XYZ = [_atom1X, _atom1Y, _atom1Z]

            # draw bond
            if atom1BondSize > 0:
                for j in range(atom1BondSize):
                    # atom [2] id
                    _atom2Id = int(_atom1BondList[j][0]) - 1
                    # atom [2] symbol
                    _atom2Symbol = _atom1BondList[j][1]
                    # atom color
                    _atom2Color = self.set_color(_atom2Symbol)
                    # atom [1] - atom [2] bond type
                    _bondType = int(_atom1BondList[j][3])

                    # set color
                    lineColor = ['w', 'w', 'w']
                    lineWidth = [4, 3, 2]
                    lineColorAtoms = [_atom1Color, _atom2Color]

                    # xyz
                    _atom2X = self.xyzList[_atom2Id, 0]
                    _atom2Y = self.xyzList[_atom2Id, 1]
                    _atom2Z = self.xyzList[_atom2Id, 2]
                    _atom2XYZ = [_atom2X, _atom2Y, _atom2Z]

                    # distance
                    _distance = self.calculate_distance(_atom1XYZ, _atom2XYZ)

                    # plot summary
                    plot_summary.append(
                        {
                            'atom1Id': _atom1Id+1,
                            'atom2Id': _atom2Id+1,
                            'atom1Symbol': str(_atom1Symbol) + str(_atom1Id+1),
                            'atom2Symbol': str(_atom2Symbol) + str(_atom2Id+1),
                            'distance': _distance
                        }
                    )

                    # line property
                    xyzMean, xyzPlane, isPlane, xyzL, perpendicularAxis = self.line_property(
                        _atom1XYZ, _atom2XYZ)

                    # ** create bond line
                    create_bond_line_version = 1
                    if create_bond_line_version == 1:
                        # bond connection (points)
                        _bondConnection, _bondTypeLog, _ = self.create_bond_line(
                            _atom1XYZ, _atom2XYZ, _bondType)

                        # size
                        _bondConnectionSize = len(_bondConnection)

                        # check
                        if _bondConnectionSize == 1:
                            _vector = _bondConnection[0]
                            ax.plot3D(_vector[0], _vector[1], _vector[2],
                                      linewidth=lineWidth[_bondType-1], c=lineColor[_bondType-1])
                        else:
                            # line color: black
                            for b in range(_bondConnectionSize):
                                _vector = _bondConnection[b]
                                ax.plot3D(_vector[0], _vector[1], _vector[2],
                                          linewidth=lineWidth[_bondType-1], c=lineColor[_bondType-1])

                    else:
                        # bond connection (points)
                        _bondConnection, _bondTypeLog = self.create_bond_line_V2(
                            _atom1XYZ, _atom2XYZ, _bondType)

                        # size
                        _bondConnectionSize = len(_bondConnection)

                        # color index
                        color_index = 0
                        # line color: black
                        for b in range(_bondConnectionSize):
                            _vector = _bondConnection[b]
                            ax.plot3D(_vector[0], _vector[1], _vector[2],
                                      linewidth=lineWidth[_bondType-1], c=lineColorAtoms[color_index])
                            # check
                            if color_index == 1:
                                color_index = 0
                            else:
                                # set color index
                                color_index += 1

            # obs show
            if obsOption[0]:
                ax.scatter3D(obsOption[1], 0, 0, s=40)

        # check
        if display_legend:
            # ax legends
            ax.legend(legend_list)
            # legend position end right
            plt.legend(loc="upper right", markerscale=0.25,
                       scatterpoints=1, fontsize=10)

        # axis setting
        ax.set_xlabel("$X$")
        ax.set_ylabel("$Y$")
        ax.set_zlabel("$Z$")

        ax.autoscale(True)
        # ax.set_aspect('auto')
        ax.set_aspect('equal')

        # set limits
        set_lim_offset = 1
        _maxVal = np.max(self.xyzList)
        ax.set_xlim(int(-_maxVal) + -set_lim_offset,
                    int(_maxVal) + set_lim_offset)
        ax.set_ylim(int(-_maxVal) + -set_lim_offset,
                    int(_maxVal) + set_lim_offset)
        ax.set_zlim(int(-_maxVal) + -set_lim_offset,
                    int(_maxVal) + set_lim_offset)

        ax.set_xscale('linear')
        ax.set_yscale('linear')

        # set angles/elevations
        ax.view_init(elev=elev, azim=azim)
        plt.show()

        # res
        return plot_summary

    def view3dobs(self, elev=None, azim=None, figSize=(10, 10), obsOption=[True, 0]):
        '''
        Draw a compound in the cartesian coordinate with observer

        Parameters
        ----------
        elev : float
            elevation angle
        azim : float
            azimuth angle
        figSize : tuple
            figure size
        obsOption : list
            [True, 0] --> show observer, 0 --> observer radius
        '''
        # 3d plot
        fig = plt.figure(figsize=figSize)
        ax = plt.axes(projection='3d')

        # atom no
        atomNo = len(self.xyzList)
        # bond no
        bondNo = len(self.atomBonds)

        # atom visualization
        for i in range(atomNo):
            # xyz
            _atomX = self.xyzList[i, 0]
            _atomY = self.xyzList[i, 1]
            _atomZ = self.xyzList[i, 2]
            # color
            # size

            # draw atom 1
            ax.scatter3D(_atomX, _atomY, _atomZ, s=40)

        # bond visualization
        for i in range(bondNo):
            # atom id
            _atom1Id = int(self.atomBonds[i]['id']) - 1
            # atom symbol
            _atom1Symbol = self.atomBonds[i]['symbol']
            # atom bond list
            _atom1BondList = self.atomBonds[i]['bonds']
            atom1BondSize = len(_atom1BondList)

            _atom1X = self.xyzList[:, 0]
            _atom1Y = self.xyzList[:, 1]
            _atom1Z = self.xyzList[:, 2]

            # draw bond
            if atom1BondSize > 0:
                for j in range(atom1BondSize):
                    # atom [2] id
                    _atom2Id = int(_atom1BondList[j][0]) - 1
                    # atom [2] symbol
                    _atom2Symbol = _atom1BondList[j][1]
                    # atom [1] - atom [2] bond type
                    _bondType = int(_atom1BondList[j][3])

                    # set color
                    lineColor = ['k', 'b', 'c']
                    lineWidth = [1, 2, 3]

                    # xyz
                    _atom2X = self.xyzList[_atom2Id, 0]
                    _atom2Y = self.xyzList[_atom2Id, 1]
                    _atom2Z = self.xyzList[_atom2Id, 2]

                    # bond connection
                    _bondConnection = self.xyzList[[_atom1Id, _atom2Id]]
                    # draw line
                    ax.plot3D(_bondConnection[:, 0], _bondConnection[:, 1], _bondConnection[:, 2],
                              color=lineColor[_bondType-1], linewidth=lineWidth[_bondType-1])

        # obs visualization
        xyzObsList = Observer.GeneratorCircleObserver(
            self._robs, self.tetaNo, self.phiNo, self.limits['teta'])[0]
        # obs size
        xyzObsSize = len(xyzObsList)
        for i in range(xyzObsSize):
            ax.scatter3D(xyzObsList[i, :, 0],
                         xyzObsList[i, :, 1], xyzObsList[i, :, 2])
            ax.plot3D(xyzObsList[i, :, 0],
                      xyzObsList[i, :, 1], xyzObsList[i, :, 2])

        # obs show
        if obsOption[0]:
            ax.scatter3D(obsOption[1], 0, 0, s=40)

        ax.view_init(elev=elev, azim=azim)
        plt.show()

    def create_line(self, xyzList1, xyzList2, t=1):
        '''
        Create a line equation and its parallel lines

        Parameters
        ----------
        xyzList1 : list
            [x1,y1,z1]
        xyzList2 : list
            [x2,y2,z2]
        t : float
            ratio between xyzList1 and xyzList2

        Returns
        -------
        r : list
            [[x1,y1,z1], [x2,y2,z2]]
        _l1 : list
            [[x1,y1,z1], [x2,y2,z2]]
        _l2 : list
            [[x1,y1,z1], [x2,y2,z2]]
        '''
        try:
            r = np.array(xyzList2) - np.array(xyzList1)

            # matrix
            rMat = np.array([xyzList1, xyzList1])

            # x
            x = r[0]*t + xyzList1[0]
            # y
            y = r[1]*t + xyzList1[1]
            # z
            z = r[2]*t + xyzList1[2]

            xL, yL, zL = 0.1*np.ones(3)
            _l1 = [[xyzList1[0]+xL, xyzList2[0]+xL], [xyzList1[1] +
                                                      yL, xyzList2[1]+yL], [xyzList1[2]+zL, xyzList2[2]+zL]]
            _l2 = [[xyzList1[0]-xL, xyzList2[0]-xL], [xyzList1[1] -
                                                      yL, xyzList2[1]-yL], [xyzList1[2]-zL, xyzList2[2]-zL]]

            # res
            return r, _l1, _l2
        except Exception as e:
            raise Exception(e)

    def calculate_distance(self, xyz1, xyz2):
        """
        Calculate the Euclidean distance between two points.

        Parameters:
        ----------
        xyz1 : list
            Coordinates of the first point [x, y, z]
        xyz2 : list
            Coordinates of the second point [x, y, z]

        Returns:
        -------
        float
            Distance between the two points
        """
        return math.sqrt((xyz2[0] - xyz1[0])**2 +
                         (xyz2[1] - xyz1[1])**2 +
                         (xyz2[2] - xyz1[2])**2)

    def set_marker_size(self, min_distance, ref_length=1, min_marker_size=200, max_marker_size=500):
        '''
        Set the plot view based on the minimum distance.

        Parameters:
        ----------
        min_distance : float
            Minimum distance between points
        ref_length : float
            Reference length for scaling
        min_marker_size : float
            Minimum marker size
        max_marker_size : float
            Maximum

        Returns:
        -------
        float
            Marker size
        '''
        scaling_factor = min_marker_size / ref_length
        marker_size = min_distance * scaling_factor

        # Ensure the marker size is within the desired range
        marker_size = min(max_marker_size, max(min_marker_size, marker_size))

        return marker_size

StructureAnalyzer()

Check geometry structure to determine 2D/3D

Parameters

xyzList: list point coordination

Returns

structureType: str 2D or 3D

Source code in molvizr3d/docs/vizr3d.py
def StructureAnalyzer(self):
    '''
    Check geometry structure to determine 2D/3D

    Parameters
    ----------
    xyzList: list
        point coordination

    Returns
    -------
    structureType: str
        2D or 3D
    '''
    try:
        # array
        xyzList = np.array(self.xyzList)
        # set
        X = xyzList[:, 0]
        Y = xyzList[:, 1]
        Z = xyzList[:, 2]

        # check plane structure (2D, 3D)
        X0 = np.abs(X).sum()
        Y0 = np.abs(Y).sum()
        Z0 = np.abs(Z).sum()
        XYZ0 = [X0, Y0, Z0]

        # perpendicular vector [x,y,z]
        perpendicularVector = [False, False, False]
        # set
        if X0 == 0:
            perpendicularVector[0] = True

        if Y0 == 0:
            perpendicularVector[1] = True

        if Z0 == 0:
            perpendicularVector[2] = True

        # status
        if True in perpendicularVector:
            structureType = '2D'
        else:
            structureType = '3D'

        # axis selection
        perpendicularAxis = []
        if perpendicularVector[0] is True:
            perpendicularAxis.append('X')
        if perpendicularVector[1] is True:
            perpendicularAxis.append('Y')
        if perpendicularVector[2] is True:
            perpendicularAxis.append('Z')

        return structureType, perpendicularAxis, perpendicularVector, XYZ0
    except Exception as e:
        raise Exception(e)

calculate_distance(xyz1, xyz2)

Calculate the Euclidean distance between two points.

Parameters:

xyz1 : list Coordinates of the first point [x, y, z] xyz2 : list Coordinates of the second point [x, y, z]

Returns:

float Distance between the two points

Source code in molvizr3d/docs/vizr3d.py
def calculate_distance(self, xyz1, xyz2):
    """
    Calculate the Euclidean distance between two points.

    Parameters:
    ----------
    xyz1 : list
        Coordinates of the first point [x, y, z]
    xyz2 : list
        Coordinates of the second point [x, y, z]

    Returns:
    -------
    float
        Distance between the two points
    """
    return math.sqrt((xyz2[0] - xyz1[0])**2 +
                     (xyz2[1] - xyz1[1])**2 +
                     (xyz2[2] - xyz1[2])**2)

create_3dframe()

Create 3d frame dimension

Source code in molvizr3d/docs/vizr3d.py
def create_3dframe(self):
    '''
    Create 3d frame dimension
    '''
    # max length
    # x
    xMin = np.min(self.xyzList[:, 0])
    xMax = np.max(self.xyzList[:, 0])
    xLen = np.abs(np.abs(xMax) - np.abs(xMin))
    # y
    yMin = np.min(self.xyzList[:, 1])
    yMax = np.max(self.xyzList[:, 1])
    yLen = np.abs(np.abs(yMax) - np.abs(yMin))
    # z
    zMin = np.min(self.xyzList[:, 2])
    zMax = np.max(self.xyzList[:, 2])
    zLen = np.abs(np.abs(zMax) - np.abs(zMin))
    # max
    xyzLenMax = np.max([xMax, yMax, zMax])
    xyzLenMin = np.min([xMin, yMin, zMin])
    xyzR = 1/xyzLenMax

    # res
    return xyzLenMax, xyzLenMin, xyzR, xLen, yLen, zLen

create_bond_line(xyz1, xyz2, bond_type, xyzL=[1, 1, 1], xyzR=0.15)

Create bond line (single, double, tipple)

Parameters

xyz1: list (x,y,z) point 1 xyz2: list (x,y,z) point 2 bond_type: int bond type (1,2,3) xyzL: list (x,y,z) length xyzR: int (x,y,z) radius

Returns

bondLines: list list of bond lines

Source code in molvizr3d/docs/vizr3d.py
def create_bond_line(self, xyz1, xyz2, bond_type, xyzL=[1, 1, 1], xyzR=0.15):
    '''
    Create bond line (single, double, tipple)

    Parameters
    ----------
    xyz1: list
        (x,y,z) point 1
    xyz2: list
        (x,y,z) point 2
    bond_type: int
        bond type (1,2,3)
    xyzL: list
        (x,y,z) length
    xyzR: int
        (x,y,z) radius

    Returns
    -------
    bondLines: list
        list of bond lines
    '''
    # bond lines
    bondLines = []
    # bond length
    bondLength = []

    xL, yL, zL = xyzR*np.array(xyzL)

    # Calculate center-to-center vector
    center_vector = np.array(xyz2) - np.array(xyz1)

    # Calculate center-to-center line
    center_line = [[xyz1[0], xyz2[0]], [
        xyz1[1], xyz2[1]], [xyz1[2], xyz2[2]]]

    if bond_type == 1:
        # bond line
        bondLines.append(center_line)
        # bond length
        _bond_length_res = self.calculate_distance(xyz1, xyz2)
        bondLength.append(_bond_length_res)

    elif bond_type == 2:
        # parallel line
        # y increase
        # center to center line
        # Calculate perpendicular vector to center vector
        perp_vector = np.array([center_vector[1], - center_vector[0], 0])
        perp_vector /= np.linalg.norm(perp_vector)

        # Calculate offset vectors
        offset_vector1 = 0.15 * perp_vector
        offset_vector2 = -0.15 * perp_vector

        # Calculate parallel lines
        _l1 = [[xyz1[0]+offset_vector1[0], xyz2[0]+offset_vector1[0]], [
            xyz1[1]+offset_vector1[1], xyz2[1]+offset_vector1[1]], [xyz1[2]+offset_vector1[2], xyz2[2]+offset_vector1[2]]]
        _l2 = [[xyz1[0]+offset_vector2[0], xyz2[0]+offset_vector2[0]], [
            xyz1[1]+offset_vector2[1], xyz2[1]+offset_vector2[1]], [xyz1[2]+offset_vector2[2], xyz2[2]+offset_vector2[2]]]

        # lines
        _l1_xyz1 = [xyz1[0]+offset_vector1[0], xyz1[1] +
                    offset_vector1[1], xyz1[2]+offset_vector1[2]]
        _l1_xyz2 = [xyz2[0]+offset_vector1[0], xyz2[1] +
                    offset_vector1[1], xyz2[2]+offset_vector1[2]]

        _l2_xyz1 = [xyz1[0]+offset_vector2[0], xyz1[1] +
                    offset_vector2[1], xyz1[2]+offset_vector2[2]]
        _l2_xyz2 = [xyz2[0]+offset_vector2[0], xyz2[1] +
                    offset_vector2[1], xyz2[2]+offset_vector2[2]]

        # bond lines
        bondLines.append(_l1)
        bondLines.append(_l2)
        # bond length
        _bond_length_res = self.calculate_distance(_l1_xyz1, _l1_xyz2)
        bondLength.append(_bond_length_res)
        _bond_length_res = self.calculate_distance(_l2_xyz1, _l2_xyz2)
        bondLength.append(_bond_length_res)

    elif bond_type == 3:
        # parallel line
        # y increase
        # line
        # Calculate perpendicular vector to center vector
        perp_vector = np.array([center_vector[1], -center_vector[0], 0])
        perp_vector /= np.linalg.norm(perp_vector)

        # Calculate offset vectors
        offset_vector1 = 0.125 * perp_vector
        offset_vector2 = -0.125 * perp_vector

        # Calculate parallel lines
        _l1 = [[xyz1[0]+offset_vector1[0], xyz2[0]+offset_vector1[0]], [
            xyz1[1]+offset_vector1[1], xyz2[1]+offset_vector1[1]], [xyz1[2]+offset_vector1[2], xyz2[2]+offset_vector1[2]]]
        _l2 = [[xyz1[0], xyz2[0]], [
            xyz1[1], xyz2[1]], [xyz1[2], xyz2[2]]]

        _l3 = [[xyz1[0]+offset_vector2[0], xyz2[0]+offset_vector2[0]], [
            xyz1[1]+offset_vector2[1], xyz2[1]+offset_vector2[1]], [xyz1[2]+offset_vector2[2], xyz2[2]+offset_vector2[2]]]

        # lines
        _l1_xyz1 = [xyz1[0]+offset_vector1[0], xyz1[1] +
                    offset_vector1[1], xyz1[2]+offset_vector1[2]]
        _l1_xyz2 = [xyz2[0]+offset_vector1[0], xyz2[1] +
                    offset_vector1[1], xyz2[2]+offset_vector1[2]]
        _l2_xyz1 = xyz1
        _l2_xyz2 = xyz2
        _l3_xyz1 = [xyz1[0]+offset_vector2[0], xyz1[1] +
                    offset_vector2[1], xyz1[2]+offset_vector2[2]]
        _l3_xyz2 = [xyz2[0]+offset_vector2[0], xyz2[1] +
                    offset_vector2[1], xyz2[2]+offset_vector2[2]]

        # bond lines
        bondLines.append(_l1)
        bondLines.append(_l2)
        bondLines.append(_l3)
        # bond length
        # bond length
        _bond_length_res = self.calculate_distance(_l1_xyz1, _l1_xyz2)
        bondLength.append(_bond_length_res)
        _bond_length_res = self.calculate_distance(_l2_xyz1, _l2_xyz2)
        bondLength.append(_bond_length_res)
        _bond_length_res = self.calculate_distance(_l3_xyz1, _l3_xyz2)
        bondLength.append(_bond_length_res)

    return bondLines, bond_type, bondLength

create_bond_line_V2(xyz1, xyz2, bond_type, xyzL=[1, 1, 1], xyzR=0.15)

Create bond line (single, double, triple)

Parameters

xyz1: list (x,y,z) point 1 xyz2: list (x,y,z) point 2 bond_type: int bond type (1,2,3) xyzL: list (x,y,z) length xyzR: int (x,y,z) radius

Returns

bondLines: list list of bond lines

Source code in molvizr3d/docs/vizr3d.py
def create_bond_line_V2(self, xyz1, xyz2, bond_type, xyzL=[1, 1, 1], xyzR=0.15):
    '''
    Create bond line (single, double, triple)

    Parameters
    ----------
    xyz1: list
        (x,y,z) point 1
    xyz2: list
        (x,y,z) point 2
    bond_type: int
        bond type (1,2,3)
    xyzL: list
        (x,y,z) length
    xyzR: int
        (x,y,z) radius

    Returns
    -------
    bondLines: list
        list of bond lines
    '''
    bondLines = []

    xL, yL, zL = xyzR*np.array(xyzL)

    # Calculate center-to-center vector
    center_vector = np.array(xyz2) - np.array(xyz1)

    # Calculate center-to-center line
    center_line = [[xyz1[0], xyz2[0]], [
        xyz1[1], xyz2[1]], [xyz1[2], xyz2[2]]]

    # Calculate midpoint
    midpoint = [(xyz1[0] + xyz2[0]) / 2, (xyz1[1] +
                                          xyz2[1]) / 2, (xyz1[2] + xyz2[2]) / 2]

    if bond_type == 1:
        # Break single bond into two lines
        bondLines.append(
            [[xyz1[0], midpoint[0]], [xyz1[1], midpoint[1]], [xyz1[2], midpoint[2]]])
        bondLines.append(
            [[midpoint[0], xyz2[0]], [midpoint[1], xyz2[1]], [midpoint[2], xyz2[2]]])

    elif bond_type == 2:
        # parallel line
        # y increase
        # center to center line
        # Calculate perpendicular vector to center vector
        perp_vector = np.array([center_vector[1], - center_vector[0], 0])
        perp_vector /= np.linalg.norm(perp_vector)

        # Calculate offset vectors
        offset_vector1 = 0.15 * perp_vector
        offset_vector2 = -0.15 * perp_vector

        # Calculate parallel lines
        _l1 = [[xyz1[0]+offset_vector1[0], xyz2[0]+offset_vector1[0]], [
            xyz1[1]+offset_vector1[1], xyz2[1]+offset_vector1[1]], [xyz1[2]+offset_vector1[2], xyz2[2]+offset_vector1[2]]]
        _l2 = [[xyz1[0]+offset_vector2[0], xyz2[0]+offset_vector2[0]], [
            xyz1[1]+offset_vector2[1], xyz2[1]+offset_vector2[1]], [xyz1[2]+offset_vector2[2], xyz2[2]+offset_vector2[2]]]

        # Break each parallel line into two lines
        bondLines.append([[xyz1[0]+offset_vector1[0], midpoint[0]+offset_vector1[0]], [
            xyz1[1]+offset_vector1[1], midpoint[1]+offset_vector1[1]], [xyz1[2]+offset_vector1[2], midpoint[2]+offset_vector1[2]]])
        bondLines.append([[midpoint[0]+offset_vector1[0], xyz2[0]+offset_vector1[0]], [
            midpoint[1]+offset_vector1[1], xyz2[1]+offset_vector1[1]], [midpoint[2]+offset_vector1[2], xyz2[2]+offset_vector1[2]]])
        bondLines.append([[xyz1[0]+offset_vector2[0], midpoint[0]+offset_vector2[0]], [
            xyz1[1]+offset_vector2[1], midpoint[1]+offset_vector2[1]], [xyz1[2]+offset_vector2[2], midpoint[2]+offset_vector2[2]]])
        bondLines.append([[midpoint[0]+offset_vector2[0], xyz2[0]+offset_vector2[0]], [
            midpoint[1]+offset_vector2[1], xyz2[1]+offset_vector2[1]], [midpoint[2]+offset_vector2[2], xyz2[2]+offset_vector2[2]]])

    elif bond_type == 3:
        # parallel line
        # y increase
        # line
        # Calculate perpendicular vector to center vector
        perp_vector = np.array([center_vector[1], -center_vector[0], 0])
        perp_vector /= np.linalg.norm(perp_vector)

        # Calculate offset vectors
        offset_vector1 = 0.125 * perp_vector
        offset_vector2 = -0.125 * perp_vector

        # Calculate parallel lines
        _l1 = [[xyz1[0]+offset_vector1[0], xyz2[0]+offset_vector1[0]], [
            xyz1[1]+offset_vector1[1], xyz2[1]+offset_vector1[1]], [xyz1[2]+offset_vector1[2], xyz2[2]+offset_vector1[2]]]
        _l2 = [[xyz1[0], xyz2[0]], [
            xyz1[1], xyz2[1]], [xyz1[2], xyz2[2]]]
        _l3 = [[xyz1[0]+offset_vector2[0], xyz2[0]+offset_vector2[0]], [
            xyz1[1]+offset_vector2[1], xyz2[1]+offset_vector2[1]], [xyz1[2]+offset_vector2[2], xyz2[2]+offset_vector2[2]]]

        # Break each parallel line into two lines
        bondLines.append([[xyz1[0]+offset_vector1[0], midpoint[0]+offset_vector1[0]], [
            xyz1[1]+offset_vector1[1], midpoint[1]+offset_vector1[1]], [xyz1[2]+offset_vector1[2], midpoint[2]+offset_vector1[2]]])
        bondLines.append([[midpoint[0]+offset_vector1[0], xyz2[0]+offset_vector1[0]], [
            midpoint[1]+offset_vector1[1], xyz2[1]+offset_vector1[1]], [midpoint[2]+offset_vector1[2], xyz2[2]+offset_vector1[2]]])
        bondLines.append([[xyz1[0], midpoint[0]], [
            xyz1[1], midpoint[1]], [xyz1[2], midpoint[2]]])
        bondLines.append([[midpoint[0], xyz2[0]], [
            midpoint[1], xyz2[1]], [midpoint[2], xyz2[2]]])
        bondLines.append([[xyz1[0]+offset_vector2[0], midpoint[0]+offset_vector2[0]], [
            xyz1[1]+offset_vector2[1], midpoint[1]+offset_vector2[1]], [xyz1[2]+offset_vector2[2], midpoint[2]+offset_vector2[2]]])
        bondLines.append([[midpoint[0]+offset_vector2[0], xyz2[0]+offset_vector2[0]], [
            midpoint[1]+offset_vector2[1], xyz2[1]+offset_vector2[1]], [midpoint[2]+offset_vector2[2], xyz2[2]+offset_vector2[2]]])

    return bondLines, bond_type

create_line(xyzList1, xyzList2, t=1)

Create a line equation and its parallel lines

Parameters

xyzList1 : list [x1,y1,z1] xyzList2 : list [x2,y2,z2] t : float ratio between xyzList1 and xyzList2

Returns

r : list [[x1,y1,z1], [x2,y2,z2]] _l1 : list [[x1,y1,z1], [x2,y2,z2]] _l2 : list [[x1,y1,z1], [x2,y2,z2]]

Source code in molvizr3d/docs/vizr3d.py
def create_line(self, xyzList1, xyzList2, t=1):
    '''
    Create a line equation and its parallel lines

    Parameters
    ----------
    xyzList1 : list
        [x1,y1,z1]
    xyzList2 : list
        [x2,y2,z2]
    t : float
        ratio between xyzList1 and xyzList2

    Returns
    -------
    r : list
        [[x1,y1,z1], [x2,y2,z2]]
    _l1 : list
        [[x1,y1,z1], [x2,y2,z2]]
    _l2 : list
        [[x1,y1,z1], [x2,y2,z2]]
    '''
    try:
        r = np.array(xyzList2) - np.array(xyzList1)

        # matrix
        rMat = np.array([xyzList1, xyzList1])

        # x
        x = r[0]*t + xyzList1[0]
        # y
        y = r[1]*t + xyzList1[1]
        # z
        z = r[2]*t + xyzList1[2]

        xL, yL, zL = 0.1*np.ones(3)
        _l1 = [[xyzList1[0]+xL, xyzList2[0]+xL], [xyzList1[1] +
                                                  yL, xyzList2[1]+yL], [xyzList1[2]+zL, xyzList2[2]+zL]]
        _l2 = [[xyzList1[0]-xL, xyzList2[0]-xL], [xyzList1[1] -
                                                  yL, xyzList2[1]-yL], [xyzList1[2]-zL, xyzList2[2]-zL]]

        # res
        return r, _l1, _l2
    except Exception as e:
        raise Exception(e)

line_mid_points(xyz1, xyz2)

Divide a line in two equal parts

Parameters

xyz1: list (x,y,z) point 1 xyz2: list (x,y,z) point 2

Returns

midPoints: list list of mid points

Source code in molvizr3d/docs/vizr3d.py
def line_mid_points(self, xyz1, xyz2):
    '''
    Divide a line in two equal parts

    Parameters
    ----------
    xyz1: list
        (x,y,z) point 1
    xyz2: list
        (x,y,z) point 2

    Returns
    -------
    midPoints: list
        list of mid points
    '''
    # Calculate midpoints
    midpoint_x = (xyz1[0] + xyz2[0]) / 2
    midpoint_y = (xyz1[1] + xyz2[1]) / 2
    midpoint_z = (xyz1[2] + xyz2[2]) / 2

    # Divide center_line into two parts
    part1 = [[xyz1[0], midpoint_x], [
        xyz1[1], midpoint_y], [xyz1[2], midpoint_z]]
    part2 = [[midpoint_x, xyz2[0]], [
        midpoint_y, xyz2[1]], [midpoint_z, xyz2[2]]]

    # Get four points
    point1 = [xyz1[0], xyz1[1], xyz1[2]]
    point2 = [midpoint_x, midpoint_y, midpoint_z]
    point3 = [midpoint_x, midpoint_y, midpoint_z]
    point4 = [xyz2[0], xyz2[1], xyz2[2]]

    # res
    return point1, point2, point3, point4, part1, part2

line_property(xyz1, xyz2)

Check a line property with which plane is parallel when res contains two True, it means the False coordination contains all elements.

Parameters

xyz1: list (x,y,z) point 1 xyz2: list (x,y,z) point 2

Returns

res: bool res

Source code in molvizr3d/docs/vizr3d.py
def line_property(self, xyz1, xyz2):
    '''
    Check a line property with which plane is parallel
    when res contains two True, it means the False coordination contains all elements.

    Parameters
    ----------
    xyz1: list
        (x,y,z) point 1
    xyz2: list
        (x,y,z) point 2

    Returns
    -------
    res: bool
        res
    '''
    try:
        # mean value
        Xm = np.mean([xyz1[0], xyz2[0]])
        Ym = np.mean([xyz1[1], xyz2[1]])
        Zm = np.mean([xyz1[2], xyz2[2]])
        xyzMean = [Xm, Ym, Zm]

        # check plane
        isSubtractZero = np.array([False, False, False])

        # points in one line
        X = xyz1[0] - xyz2[0]
        Y = xyz1[1] - xyz2[1]
        Z = xyz1[2] - xyz2[2]
        xyzPlane = [X, Y, Z]

        # axis vector
        xyzL = np.array([0, 0, 0])

        # set
        # axis selection
        perpendicularAxis = np.array([False, False, False])
        if X == 0:
            isSubtractZero[0] = True
            perpendicularAxis[0] = True
            # xyzL = xyzL + np.array(1, 1, 0)

        if Y == 0:
            isSubtractZero[1] = True
            perpendicularAxis[1] = True
            # xyzL = xyzL + np.array(1, 1, 0)

        if Z == 0:
            isSubtractZero[2] = True
            perpendicularAxis[2] = True
            # xyzL = xyzL + np.array(1, 0, 1)

        # set xyzL
        xyzL = isSubtractZero.astype(int)

        return xyzMean, xyzPlane, isSubtractZero, xyzL, perpendicularAxis

    except Exception as e:
        raise Exception(e)

set_color(atom_symbol)

Set a color for each compound taken from https://en.wikipedia.org/wiki/CPK_coloring

Parameters

atom_symbol: str atom symbol

Returns

color: str atom color

Source code in molvizr3d/docs/vizr3d.py
def set_color(self, atom_symbol):
    '''
    Set a color for each compound
    taken from https://en.wikipedia.org/wiki/CPK_coloring

    Parameters
    ----------
    atom_symbol: str
        atom symbol

    Returns
    -------
    color: str
        atom color
    '''
    colors = {
        "H": '#ffffff',
        "C": '#BCBCBC',
        "N": '#0586f6',
        "O": '#f6052a',
        "F": '#2dd930',
        "Cl": '#2dd930',
        "Br": '#950e0e',
        "I": '#360e89',
        "He": '#3dbaf1',
        "Ne": '#3dbaf1',
        "Ar": '#3dbaf1',
        "Kr": '#3dbaf1',
        "Xe": '#3dbaf1',
        "P": '#f1a03d',
        "S": '#f1ef3d',
        "B": '#efc867',
        "Li": '#6b3ccb',
        "Na": '#6b3ccb',
        "K": '#6b3ccb',
        "Rb": '#6b3ccb',
        "Cs": '#6b3ccb',
        "Fr": '#6b3ccb',
        "Be": '#1c881e',
        "Mg": '#1c881e',
        "Ca": '#1c881e',
        "Sr": '#1c881e',
        "Ba": '#1c881e',
        "Ra": '#1c881e',
        "Ti": '#3d3e40',
        "Fe": '#a48620',
        "other": '#a729ba'
    }

    # check
    _color = colors.get(str(atom_symbol))
    if _color is None:
        return colors.get(str('other'))
    else:
        return _color

set_marker_size(min_distance, ref_length=1, min_marker_size=200, max_marker_size=500)

Set the plot view based on the minimum distance.

Parameters:

min_distance : float Minimum distance between points ref_length : float Reference length for scaling min_marker_size : float Minimum marker size max_marker_size : float Maximum

Returns:

float Marker size

Source code in molvizr3d/docs/vizr3d.py
def set_marker_size(self, min_distance, ref_length=1, min_marker_size=200, max_marker_size=500):
    '''
    Set the plot view based on the minimum distance.

    Parameters:
    ----------
    min_distance : float
        Minimum distance between points
    ref_length : float
        Reference length for scaling
    min_marker_size : float
        Minimum marker size
    max_marker_size : float
        Maximum

    Returns:
    -------
    float
        Marker size
    '''
    scaling_factor = min_marker_size / ref_length
    marker_size = min_distance * scaling_factor

    # Ensure the marker size is within the desired range
    marker_size = min(max_marker_size, max(min_marker_size, marker_size))

    return marker_size

set_plot_scale()

Set plot scale

Source code in molvizr3d/docs/vizr3d.py
def set_plot_scale(self):
    '''
    Set plot scale
    '''
    # atom no
    atomNo = len(self.xyzList)
    # bond no
    bondNo = len(self.atomBonds)

    # bond length list
    bondLengthList = []

    # *** using bond block
    for i in range(bondNo):
        # atom id
        _atom1Id = int(self.atomBonds[i]['id']) - 1
        # atom symbol
        _atom1Symbol = self.atomBonds[i]['symbol']
        # atom color
        _atom1Color = self.set_color(_atom1Symbol)
        # atom bond list
        _atom1BondList = self.atomBonds[i]['bonds']
        atom1BondSize = len(_atom1BondList)

        _atom1X = self.xyzList[_atom1Id, 0]
        _atom1Y = self.xyzList[_atom1Id, 1]
        _atom1Z = self.xyzList[_atom1Id, 2]
        _atom1XYZ = [_atom1X, _atom1Y, _atom1Z]

        # draw bond
        if atom1BondSize > 0:
            for j in range(atom1BondSize):
                # atom [2] id
                _atom2Id = int(_atom1BondList[j][0]) - 1
                # atom [2] symbol
                _atom2Symbol = _atom1BondList[j][1]
                # atom color
                _atom2Color = self.set_color(_atom2Symbol)
                # atom [1] - atom [2] bond type
                _bondType = int(_atom1BondList[j][3])

                # xyz
                _atom2X = self.xyzList[_atom2Id, 0]
                _atom2Y = self.xyzList[_atom2Id, 1]
                _atom2Z = self.xyzList[_atom2Id, 2]
                _atom2XYZ = [_atom2X, _atom2Y, _atom2Z]

                # bond connection (points)
                _bondConnection, _bondTypeLog, _bondLengths = self.create_bond_line(
                    _atom1XYZ, _atom2XYZ, _bondType)

                # save bond length
                bondLengthList.append(_bondLengths)

    # check bond length list
    if len(bondLengthList) > 0:
        # flatten list
        bondLengthList_flatten = sum(bondLengthList, [])

        # max bond length
        maxBondLength = max(bondLengthList_flatten)
        # min bond length
        minBondLength = min(bondLengthList_flatten)
        # mean bond length
        meanBondLength = np.mean(bondLengthList_flatten)
        # median bond length
        medianBondLength = np.median(bondLengthList_flatten)

        # set plot scale
        self.plotScale = [minBondLength, maxBondLength,
                          meanBondLength, medianBondLength]

set_size(symbol, _sy=300, _s=1)

Set atom size (spherical shape)

Parameters

symbol: str atom symbol _s: int size

Returns

size: int size

Source code in molvizr3d/docs/vizr3d.py
def set_size(self, symbol, _sy=300, _s=1):
    '''
    Set atom size (spherical shape)

    Parameters
    ----------
    symbol: str
        atom symbol
    _s: int
        size

    Returns
    -------
    size: int
        size
    '''
    _sy = 300
    _sx = 0.50*_sy

    sizes = {
        "H": _s*_sx,
        "C": _s*_sy,
        "N": _s*_sy,
        "O": _s*_sy,
        "F": _s*_sy,
        "Cl": _s*_sx,
        "Br": _s*_sy,
        "I": _s*_sy,
        "He": _s*_sy,
        "Ne": _s*_sy,
        "Ar": _s*_sy,
        "Kr": _s*_sy,
        "Xe": _s*_sy,
        "P": _s*_sy,
        "S": _s*_sy,
        "B": _s*_sy,
        "Li": _s*_sy,
        "Na": _s*_sy,
        "K": _s*_sy,
        "Rb": _s*_sy,
        "Cs": _s*_sy,
        "Fr": _s*_sy,
        "Be": _s*_sy,
        "Mg": _s*_sy,
        "Ca": _s*_sy,
        "Sr": _s*_sy,
        "Ba": _s*_sy,
        "Ra": _s*_sy,
        "Ti": _s*_sy,
        "Fe": _s*_sy,
        "other": _s*_sy,
    }

    _size = sizes.get(symbol)
    if _size is None:
        _sizeSet = int(sizes.get('other'))
    else:
        _sizeSet = int(_size)

    return _sizeSet

view3d(elev=None, azim=None, figSize='default', obsOption=[False, 0], dpi=100, pixel_width=800, pixel_height=600, bg_color='#090A0B', display_legend=True)

Draw a compound in the cartesian coordinate atomElements atom symbol atomBonds atom bonds (bond blocks) xyzList atom position in the cartesian coordinate figSize=(10, 10) plt 3d setting obsOption=[False, 0] display center point [0,0,0]

Parameters

elev: int elevation of the view angle (default: 30) azim: int azimuthal angle of the view angle (default: 30) figSize: tuple figure size obsOption: list display center point [False,0] dpi: int dots per inch pixel_width: int width of the figure in pixels pixel_height: int height of the figure in pixels bg_color: str background color display_legend: bool display legend

Returns

fig: figure figure

Source code in molvizr3d/docs/vizr3d.py
def view3d(self, elev=None, azim=None, figSize='default', obsOption=[False, 0],
           dpi=100, pixel_width=800, pixel_height=600, bg_color='#090A0B', display_legend=True):
    '''
    Draw a compound in the cartesian coordinate
    atomElements atom symbol
    atomBonds atom bonds (bond blocks)
    xyzList atom position in the cartesian coordinate
    figSize=(10, 10) plt 3d setting
    obsOption=[False, 0] display center point [0,0,0]

    Parameters
    ----------
    elev: int
        elevation of the view angle (default: 30)
    azim: int
        azimuthal angle of the view angle (default: 30)
    figSize: tuple
        figure size
    obsOption: list
        display center point [False,0]
    dpi: int
        dots per inch
    pixel_width: int
        width of the figure in pixels
    pixel_height: int
        height of the figure in pixels
    bg_color: str
        background color
    display_legend: bool
        display legend

    Returns
    -------
    fig: figure
        figure
    '''
    # plot summary
    plot_summary = []
    # 3d plot
    if figSize == 'default':
        fig = plt.figure(figsize=(6, 6), facecolor=f'{bg_color}')
    else:
        fig_size_inches = (pixel_width / dpi, pixel_height / dpi)
        fig = plt.figure(figsize=fig_size_inches,
                         dpi=dpi, facecolor=f'{bg_color}')

    # remove paddings
    fig.tight_layout(pad=0)

    # projection
    ax = plt.axes(projection='3d')

    # Adjust the layout to fill the entire figure
    fig.subplots_adjust(left=0, right=1, top=1, bottom=0)

    # axis display
    plt.axis('off')
    # color
    ax_color = f'{bg_color}'
    ax.set_facecolor(ax_color)

    # legend
    legend_list = []

    # marker label
    marker_labels = []

    # atom no
    atomNo = len(self.xyzList)
    # bond no
    bondNo = len(self.atomBonds)

    # create 3d frame
    xyzLenMax, xyzLenMin, xyzR, xLen, yLen, zLen = self.create_3dframe()

    # *** plot scale
    plot_scale_res = self.set_plot_scale()
    # min bond length
    min_bond_length = self.plotScale[0]
    # max bond length
    max_bond_length = self.plotScale[1]
    # set marker size
    marker_size_0 = self.set_marker_size(min_bond_length, max_bond_length)

    # *** atom visualization
    for i in range(atomNo):
        # xyz
        _atom1X = self.xyzList[i, 0]
        _atom1Y = self.xyzList[i, 1]
        _atom1Z = self.xyzList[i, 2]
        _atom1XYZ = [_atom1X, _atom1Y, _atom1Z]

        # color
        # atom id
        _atomId = int(i+1)
        # symbol
        _atomSymbol = str(self.atomElements[i]).strip()
        # size
        _atomSize = self.set_size(_atomSymbol, _sy=marker_size_0)
        # color
        _atomColor = self.set_color(_atomSymbol)

        # atom mark
        atomMark = str(_atomSymbol) + str(_atomId)

        # atom label
        marker_labels.append(atomMark)

        # marker edgecolor
        marker_edgecolor = str('#5C5C5C')

        # legend list
        if _atomSymbol not in legend_list:
            legend_list.append(_atomSymbol)

            # draw atom 1
            ax.scatter3D(_atom1X, _atom1Y, _atom1Z,
                         label=_atomSymbol, s=_atomSize, color=_atomColor, edgecolors=marker_edgecolor)
        else:
            # draw atom 1
            ax.scatter3D(_atom1X, _atom1Y, _atom1Z,
                         s=_atomSize, color=_atomColor, edgecolors=marker_edgecolor)

    # *** atom label display
    # for i, label in enumerate(marker_labels):
    #     # xyz
    #     _atom1X = self.xyzList[i, 0]
    #     _atom1Y = self.xyzList[i, 1]
    #     _atom1Z = self.xyzList[i, 2]
    #     # set
    #     ax.text(_atom1X, _atom1Y, _atom1Z, label, ha='left',
    #             va='center', color='red', fontsize=12)

    # reset
    i = 0

    # *** bond visualization
    # *** using bond block
    for i in range(bondNo):
        # atom id
        _atom1Id = int(self.atomBonds[i]['id']) - 1
        # atom symbol
        _atom1Symbol = self.atomBonds[i]['symbol']
        # atom color
        _atom1Color = self.set_color(_atom1Symbol)
        # atom bond list
        _atom1BondList = self.atomBonds[i]['bonds']
        atom1BondSize = len(_atom1BondList)

        _atom1X = self.xyzList[_atom1Id, 0]
        _atom1Y = self.xyzList[_atom1Id, 1]
        _atom1Z = self.xyzList[_atom1Id, 2]
        _atom1XYZ = [_atom1X, _atom1Y, _atom1Z]

        # draw bond
        if atom1BondSize > 0:
            for j in range(atom1BondSize):
                # atom [2] id
                _atom2Id = int(_atom1BondList[j][0]) - 1
                # atom [2] symbol
                _atom2Symbol = _atom1BondList[j][1]
                # atom color
                _atom2Color = self.set_color(_atom2Symbol)
                # atom [1] - atom [2] bond type
                _bondType = int(_atom1BondList[j][3])

                # set color
                lineColor = ['w', 'w', 'w']
                lineWidth = [4, 3, 2]
                lineColorAtoms = [_atom1Color, _atom2Color]

                # xyz
                _atom2X = self.xyzList[_atom2Id, 0]
                _atom2Y = self.xyzList[_atom2Id, 1]
                _atom2Z = self.xyzList[_atom2Id, 2]
                _atom2XYZ = [_atom2X, _atom2Y, _atom2Z]

                # distance
                _distance = self.calculate_distance(_atom1XYZ, _atom2XYZ)

                # plot summary
                plot_summary.append(
                    {
                        'atom1Id': _atom1Id+1,
                        'atom2Id': _atom2Id+1,
                        'atom1Symbol': str(_atom1Symbol) + str(_atom1Id+1),
                        'atom2Symbol': str(_atom2Symbol) + str(_atom2Id+1),
                        'distance': _distance
                    }
                )

                # line property
                xyzMean, xyzPlane, isPlane, xyzL, perpendicularAxis = self.line_property(
                    _atom1XYZ, _atom2XYZ)

                # ** create bond line
                create_bond_line_version = 1
                if create_bond_line_version == 1:
                    # bond connection (points)
                    _bondConnection, _bondTypeLog, _ = self.create_bond_line(
                        _atom1XYZ, _atom2XYZ, _bondType)

                    # size
                    _bondConnectionSize = len(_bondConnection)

                    # check
                    if _bondConnectionSize == 1:
                        _vector = _bondConnection[0]
                        ax.plot3D(_vector[0], _vector[1], _vector[2],
                                  linewidth=lineWidth[_bondType-1], c=lineColor[_bondType-1])
                    else:
                        # line color: black
                        for b in range(_bondConnectionSize):
                            _vector = _bondConnection[b]
                            ax.plot3D(_vector[0], _vector[1], _vector[2],
                                      linewidth=lineWidth[_bondType-1], c=lineColor[_bondType-1])

                else:
                    # bond connection (points)
                    _bondConnection, _bondTypeLog = self.create_bond_line_V2(
                        _atom1XYZ, _atom2XYZ, _bondType)

                    # size
                    _bondConnectionSize = len(_bondConnection)

                    # color index
                    color_index = 0
                    # line color: black
                    for b in range(_bondConnectionSize):
                        _vector = _bondConnection[b]
                        ax.plot3D(_vector[0], _vector[1], _vector[2],
                                  linewidth=lineWidth[_bondType-1], c=lineColorAtoms[color_index])
                        # check
                        if color_index == 1:
                            color_index = 0
                        else:
                            # set color index
                            color_index += 1

        # obs show
        if obsOption[0]:
            ax.scatter3D(obsOption[1], 0, 0, s=40)

    # check
    if display_legend:
        # ax legends
        ax.legend(legend_list)
        # legend position end right
        plt.legend(loc="upper right", markerscale=0.25,
                   scatterpoints=1, fontsize=10)

    # axis setting
    ax.set_xlabel("$X$")
    ax.set_ylabel("$Y$")
    ax.set_zlabel("$Z$")

    ax.autoscale(True)
    # ax.set_aspect('auto')
    ax.set_aspect('equal')

    # set limits
    set_lim_offset = 1
    _maxVal = np.max(self.xyzList)
    ax.set_xlim(int(-_maxVal) + -set_lim_offset,
                int(_maxVal) + set_lim_offset)
    ax.set_ylim(int(-_maxVal) + -set_lim_offset,
                int(_maxVal) + set_lim_offset)
    ax.set_zlim(int(-_maxVal) + -set_lim_offset,
                int(_maxVal) + set_lim_offset)

    ax.set_xscale('linear')
    ax.set_yscale('linear')

    # set angles/elevations
    ax.view_init(elev=elev, azim=azim)
    plt.show()

    # res
    return plot_summary

view3dobs(elev=None, azim=None, figSize=(10, 10), obsOption=[True, 0])

Draw a compound in the cartesian coordinate with observer

Parameters

elev : float elevation angle azim : float azimuth angle figSize : tuple figure size obsOption : list [True, 0] --> show observer, 0 --> observer radius

Source code in molvizr3d/docs/vizr3d.py
def view3dobs(self, elev=None, azim=None, figSize=(10, 10), obsOption=[True, 0]):
    '''
    Draw a compound in the cartesian coordinate with observer

    Parameters
    ----------
    elev : float
        elevation angle
    azim : float
        azimuth angle
    figSize : tuple
        figure size
    obsOption : list
        [True, 0] --> show observer, 0 --> observer radius
    '''
    # 3d plot
    fig = plt.figure(figsize=figSize)
    ax = plt.axes(projection='3d')

    # atom no
    atomNo = len(self.xyzList)
    # bond no
    bondNo = len(self.atomBonds)

    # atom visualization
    for i in range(atomNo):
        # xyz
        _atomX = self.xyzList[i, 0]
        _atomY = self.xyzList[i, 1]
        _atomZ = self.xyzList[i, 2]
        # color
        # size

        # draw atom 1
        ax.scatter3D(_atomX, _atomY, _atomZ, s=40)

    # bond visualization
    for i in range(bondNo):
        # atom id
        _atom1Id = int(self.atomBonds[i]['id']) - 1
        # atom symbol
        _atom1Symbol = self.atomBonds[i]['symbol']
        # atom bond list
        _atom1BondList = self.atomBonds[i]['bonds']
        atom1BondSize = len(_atom1BondList)

        _atom1X = self.xyzList[:, 0]
        _atom1Y = self.xyzList[:, 1]
        _atom1Z = self.xyzList[:, 2]

        # draw bond
        if atom1BondSize > 0:
            for j in range(atom1BondSize):
                # atom [2] id
                _atom2Id = int(_atom1BondList[j][0]) - 1
                # atom [2] symbol
                _atom2Symbol = _atom1BondList[j][1]
                # atom [1] - atom [2] bond type
                _bondType = int(_atom1BondList[j][3])

                # set color
                lineColor = ['k', 'b', 'c']
                lineWidth = [1, 2, 3]

                # xyz
                _atom2X = self.xyzList[_atom2Id, 0]
                _atom2Y = self.xyzList[_atom2Id, 1]
                _atom2Z = self.xyzList[_atom2Id, 2]

                # bond connection
                _bondConnection = self.xyzList[[_atom1Id, _atom2Id]]
                # draw line
                ax.plot3D(_bondConnection[:, 0], _bondConnection[:, 1], _bondConnection[:, 2],
                          color=lineColor[_bondType-1], linewidth=lineWidth[_bondType-1])

    # obs visualization
    xyzObsList = Observer.GeneratorCircleObserver(
        self._robs, self.tetaNo, self.phiNo, self.limits['teta'])[0]
    # obs size
    xyzObsSize = len(xyzObsList)
    for i in range(xyzObsSize):
        ax.scatter3D(xyzObsList[i, :, 0],
                     xyzObsList[i, :, 1], xyzObsList[i, :, 2])
        ax.plot3D(xyzObsList[i, :, 0],
                  xyzObsList[i, :, 1], xyzObsList[i, :, 2])

    # obs show
    if obsOption[0]:
        ax.scatter3D(obsOption[1], 0, 0, s=40)

    ax.view_init(elev=elev, azim=azim)
    plt.show()