Skip to content

Conversation

Erykiusz
Copy link

No description provided.

@karolamik13
Copy link
Owner

Please move non-standard imports inside the functions and use LOGGER to check whether the package is installed. If not, provide information on which particular package needs to be installed to use this function. If we have those imports in the current form, I immediately have an error when importing ProDy (see below).

In [1]: from prody import *

ModuleNotFoundError Traceback (most recent call last)
Cell In[1], line 1
----> 1 from prody import *

File ~/test_ProDy/ET_ProDy/ProDy/prody/init.py:88
84 all.append('atomic')
86 from .atomic import SELECT
---> 88 from . import proteins
89 from .proteins import *
90 all.extend(proteins.all)

File ~/test_ProDy/ET_ProDy/ProDy/prody/proteins/init.py:253
250 from .starfile import *
251 all.extend(starfile.all)
--> 253 from . import interactions
254 from .interactions import *
255 all.extend(interactions.all)

File ~/test_ProDy/ET_ProDy/ProDy/prody/proteins/interactions.py:37
35 import subprocess
36 import heapq
---> 37 import open3d as o3d
38 from collections import deque
39 from scipy.interpolate import CubicSpline

ModuleNotFoundError: No module named 'open3d'

@karolamik13
Copy link
Owner

I would suggest changing the name of the main function detect_channels to calcChannels. ProDy is using calcXXX (to compute something) or getXXX (if we want raw numbers, etc.).

Here:
detect_channels(
protein,
r1=3,
r2=1.25,
min_depth=10,
bottleneck=1,
sparsity=15,
output_path=None,
visualizer=None,
stl_path=None,
)

in Prody we are using "atoms" as the parameter with protein structure.

See here:
:arg atoms: an Atomic object from which residues are selected
:type atoms: :class:.Atomic

@karolamik13
Copy link
Owner

Usually, in ProDy, some results are returned. See below...when I am calling channels, I should have some results on which I could do some further analysis.. for example, to check the volume of the channels or which residues are forming the channel, etc. We should be able to have access to each channel among those 9 which were identified. Dictionary maybe?

In [10]: p = parsePDB('1tqn.pdb')
@> 3999 atoms and 1 coordinate set(s) were parsed in 0.12s.

In [11]: p_prot = p.select('protein')

In [12]: p_prot
Out[12]: <Selection: 'protein' from 1tqn (3766 atoms)>

In [13]: channels = detect_channels(p_prot)
9
Detected 9 channels.
No output path given.

In [14]: channels

@karolamik13
Copy link
Owner

karolamik13 commented Aug 20, 2024

visualizer='channels' - that looks nice.
Can we have another option: if we set it to visualizer='True', we will see the channels + protein in the NewCartoon representation or any other representation to simply see where they are located?

I don't understand how to obtain stl file. Is it created automatically when not set to None?

When I did this:
In [24]: channels = detect_channels(p_prot, output_path='results_channels.pdb', visualizer='channels', st
...: l_path='results_stl.stl')
9
Detected 9 channels.
Saving results to results_channels.pdb
[Open3D WARNING] Unable to load file results_stl.stl with ASSIMP
[Open3D WARNING] The number of points is 0 when creating axis-aligned bounding box.

I received only channels without protein structure on the visualization and stl file was not created.

@karolamik13 karolamik13 self-requested a review August 20, 2024 07:51
Copy link
Owner

@karolamik13 karolamik13 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Except for the comments above, the channel prediction looks good. I am receiving similar results. When the comments will be applied I will test it again on different structures and with different parameters.

@Erykiusz
Copy link
Author

The stl file is created from the run_vmd_script command or the tcl script itself. 'stl_path' is an input parameter with a 3D model of the NewCartoon representation of the protein. When the parameter is set to None, instead of the protein, a triangle mesh approximating the protein surface will be used. When the program detects an stl file with a protein model, it automatically displays the protein instead of the approximated mesh.

@Erykiusz
Copy link
Author

New changes:
-added new function getChannelsParameters which provides details about lengths and bottlenecks of channels
-changed names of functions: runVmdScript and calcChannels
-fixed runVmdScript so it now works
-moved libriaries inside the function so they can be chekked with logger
-calcChannels now returns channels in a list object, also returns surface of a molecule. Added two new parameters: 'vis_channels' and 'surface', enabling to use the function in only visualizer mode. If 'vis_channels' parameter is not set to None, only visualization of channels inputed in 'vis_channels' will be performed. This enables to visualize only channels of interest. Example use:

protein_path = "C:\Users\User\Desktop\1tqn.pdb"
vmd_path = "C:\Program Files\VMD\vmd.exe"
script_path = "C:\Users\User\vmd_script.tcl"
stl_path = "C:\Users\User\Desktop\result.stl" #this file will be created in runVmdScript
prody.runVmdScript(vmd_path, protein_path, script_path, stl_path)

protein = prody.parsePDB(protein_path)
channels, surface = prody.calcChannels(protein) #calculations
prody.calcChannels(protein, vis_channels = channels, surface = surface, stl_path = stl_path) #visualization only
lengths, bottlenecks = prody.getChannelsParameters(channels)

I didnt yet add volume of channels in getChannelsParameters because it will take a bit longer to implement.

@karolamik13
Copy link
Owner

Thank you for the improvements.

Now I am testing the functions again:

In [9]: channels = calcChannels(atoms)
Detected 10 channels.
No output path given.

In [10]: channels
Out[10]:
([<prody.proteins.interactions.Channel at 0x7fc51f663cd0>,
<prody.proteins.interactions.Channel at 0x7fc51f663bb0>,
<prody.proteins.interactions.Channel at 0x7fc51f663af0>,
<prody.proteins.interactions.Channel at 0x7fc51f663a30>,
<prody.proteins.interactions.Channel at 0x7fc51f663970>,
<prody.proteins.interactions.Channel at 0x7fc51f663850>,
<prody.proteins.interactions.Channel at 0x7fc51f6635b0>,
<prody.proteins.interactions.Channel at 0x7fc51f663430>,
<prody.proteins.interactions.Channel at 0x7fc51f663370>,
<prody.proteins.interactions.Channel at 0x7fc51f6632b0>],
array([[5136, 5139, 5140, 5137],
[5138, 5136, 5139, 5137],
[5138, 5139, 5140, 5137],
...,
[1163, 3246, 3249, 3248],
[1163, 1164, 3246, 3249],
[1163, 3246, 3284, 3248]], dtype=int32))

It's nice that we have some results now. Can we somehow distinguish different channels? We have 10 which were detected in the structure I tested.

Also, "No output path given." I would change it to LOGGER info. Something like: To obtain a PDB file with the results please use...this and this parameter, etc. (or some other information to explain more what to do to actually obtain some visualization of the channels and not only the number.

@Erykiusz
Copy link
Author

To distinguish between channels we can use getChannelsParameters and check the lengths. Parameters are outputted to a list which order corresponds to the order of channels. For example, if we want to get only the longest channel, we would check the lengths of channels and get an index of the longest channels (for example 3), and then get the 3rd channel by doing channels[3] and input it to the visualizer by prody.calcChannels(protein, vis_channels = channels[3], surface = surface). I dont really have an idea to distinguish the channels in a different way.

@karolamik13
Copy link
Owner

Hi James @jamesmkrieger
this is the first version of the channel detector for ProDy.
Let us know if you have any suggestions. It is still under development.
In the end, when everything is working fine, we might want to create a class for this kind of calculation and move channels from interaction.py to the separated file.

@karolamik13
Copy link
Owner

@Erykiusz could you provide an example line by line? (even just commands)
I am trying things, but I have errors.

Also, can we have access to the atoms (=channels) that are saved as PDB files? It would be very useful to have coordinates of those atoms and then we can use exwithin in select to provide the residues which are forming the channel. And it would be good to have those atoms separated by channels.

@Erykiusz
Copy link
Author

Erykiusz commented Aug 21, 2024

To get only selected channels we can do this:
protein = prody.parsePDB(protein_path)

Calculations:
channels, surface = prody.calcChannels(protein)
lengths, bottlenecks = prody.getChannelsParameters(channels)

Now we got a list of lengths of the channels. Lets say we want to see only 3rd and 4th channel. So we do:
selected_channels = [channels[3], channels[4]]

Now we visualize:
prody.calcChannels(protein, vis_channels = selected_channels, surface = surface)

I will add the option to see the atoms of channels next time I will be working on it.

@karolamik13
Copy link
Owner

Now it is working fine. Thank you.

@jamesmkrieger
Copy link

Great. I’ll have a look.

I don’t think it needs to go in a class. We have many functionalities in prody that are just functions too.

@jamesmkrieger
Copy link

Please move non-standard imports inside the functions and use LOGGER to check whether the package is installed. If not, provide information on which particular package needs to be installed to use this function. If we have those imports in the current form, I immediately have an error when importing ProDy (see below).

In [1]: from prody import *

ModuleNotFoundError Traceback (most recent call last) Cell In[1], line 1 ----> 1 from prody import *

File ~/test_ProDy/ET_ProDy/ProDy/prody/init.py:88 84 all.append('atomic') 86 from .atomic import SELECT ---> 88 from . import proteins 89 from .proteins import * 90 all.extend(proteins.all)

File ~/test_ProDy/ET_ProDy/ProDy/prody/proteins/init.py:253 250 from .starfile import * 251 all.extend(starfile.all) --> 253 from . import interactions 254 from .interactions import * 255 all.extend(interactions.all)

File ~/test_ProDy/ET_ProDy/ProDy/prody/proteins/interactions.py:37 35 import subprocess 36 import heapq ---> 37 import open3d as o3d 38 from collections import deque 39 from scipy.interpolate import CubicSpline

ModuleNotFoundError: No module named 'open3d'

I wouldn’t use LOGGER to report modules not installed. We need to raise an ImportError inside the function saying that the user needs that module to run the function

from scipy.spatial import Voronoi, Delaunay
from pathlib import Path

if not check_and_import('heapq'):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check packages before trying to import them to not get errors

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can probably also do this with a loop over a list of names

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could also be a general function in prody.utilities and I was thinking of adding import_command inside too

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I now have the following code that seems to work:

    def check_and_import(package_name, import_command=None):
        """Check for package and import it if possible and return **True**.
        Otherwise, return **False
        
        :arg package_name: name of package
        :type package_name: str

        :arg import_command: optional command to import submodules or with an alias
            default **None** means use "import {0}".format(package_name)
        :type import_command: None, str
        """

        if not isinstance(package_name, str):
            raise TypeError('package_name should be a string')
        
        if not isinstance(import_command, (type(None), str)):
            raise TypeError('import_command should be None or a string')

        import importlib.util
        if importlib.util.find_spec(package_name) is None:
            LOGGER.warn(f"Package '{package_name}' is not installed. Please install it to use this function.")
            return False
        
        if import_command is None:
            exec('import {0}'.format(package_name))
        else:
            exec(import_command)

        return True
    
    required = [['heapq', None], ['open3d', 'import open3d as o3d'], ['collections', 'from collections import deque'],
                ['scipy', 'from scipy.interpolate import CubicSpline; from scipy.spatial import Voronoi, Delaunay'],
                ['pathlib', 'from pathlib import Path']]
    
    missing = []
    errorMsg = None
    for (name, command) in required:
        if not check_and_import(name, command):
            missing.append(name)
            if errorMsg is None:
                errorMsg = 'To run calcChannels, please install {0}'.format(missing[0])
            else:
                errorMsg += ', ' + name

    if len(missing) > 0:
        if len(missing) > 1:
            errorMsg = ', '.join(errorMsg.split(', ')[:-1]) + ' and ' + errorMsg.split(', ')[-1]
        raise ImportError(errorMsg)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact, we then don't need the logger step at all. The current output is as follows:

channels, surface = prody.calcChannels(protein)
@> WARNING Package 'open3d' is not installed. Please install it to use this function.
---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
Cell In[54], line 1
----> 1 channels, surface = prody.calcChannels(protein)

File ~/software/scipion3/software/em/prody-github/ProDy/prody/proteins/interactions.py:4511, in calcChannels(atoms, r1, r2, min_depth, bottleneck, sparsity, output_path, visualizer, stl_path, vis_channels, surface)
   4509     if len(missing) > 1:
   4510         errorMsg = ', '.join(errorMsg.split(', ')[:-1]) + ' and ' + errorMsg.split(', ')[-1]
-> 4511     raise ImportError(errorMsg)
   4513 class State:
   4514     def __init__(self, simplices, neighbors, vertices):

ImportError: To run calcChannels, please install open3d

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, it looks like importing inside the check function doesn't work. Sorry.

Now my code is the following:

    def check_and_import(package_name):
        """Check for package and import it if possible and return **True**.
        Otherwise, return **False
        
        :arg package_name: name of package
        :type package_name: str

        :arg import_command: optional command to import submodules or with an alias
            default **None** means use "import {0}".format(package_name)
        :type import_command: None, str
        """
        if not isinstance(package_name, str):
            raise TypeError('package_name should be a string')

        import importlib.util
        if importlib.util.find_spec(package_name) is None:
            LOGGER.warn(f"Package '{package_name}' is not installed. Please install it to use this function.")
            return False
        return True
    
    required = ['heapq', 'open3d', 'collections', 'scipy', 'pathlib']
    missing = []
    errorMsg = None
    for name in required:
        if not check_and_import(name):
            missing.append(name)
            if errorMsg is None:
                errorMsg = 'To run calcChannels, please install {0}'.format(missing[0])
            else:
                errorMsg += ', ' + name

    if len(missing) > 0:
        if len(missing) > 1:
            errorMsg = ', '.join(errorMsg.split(', ')[:-1]) + ' and ' + errorMsg.split(', ')[-1]
        raise ImportError(errorMsg)

    import heapq
    import open3d as o3d
    from collections import deque
    from scipy.interpolate import CubicSpline
    from scipy.spatial import Voronoi, Delaunay
    from pathlib import Path

@jamesmkrieger
Copy link

Ok. I can see the benefit of logging all the packages needed and raising one error at the end rather than going through one by one

@jamesmkrieger
Copy link

Probably this should go in its own file not the interactions one. If anything, it’s more related to watfinder and it would be nice to have a way of comparing results and checking for waters along these channels. It would be nice to include ions too

@karolamik13
Copy link
Owner

All atoms that are not 'HETATM' are analyzed. Depends on which one you provide as a parsed one. If ions have 'ATOMS' instead of 'HETATM' they should be analyzed too. I can check that later and confirm.

@karolamik13
Copy link
Owner

James, you are right. It will fit better to waterbridges.py.
In such a way, we would not have to create additional file.

@jamesmkrieger
Copy link

All atoms that are not 'HETATM' are analyzed. Depends on which one you provide as a parsed one. If ions have 'ATOMS' instead of 'HETATM' they should be analyzed too. I can check that later and confirm.

Ions are usually HETATM. We also don’t want them treated like protein atoms for defining the channels. We’d want to look at them afterwards to see if they occupy the channels.

@Erykiusz
Copy link
Author

Built-in visualizer can show a protein model from an stl file on top of the channels. So for example we can compute channels without ions or any HETATM atoms (which is done by default) and then visualize the computed channels with a model that includes additional atoms. This is actually an approach which I have been using for testing. Below I'm sending a screenshot showing how it looks like.
wynik

@Erykiusz
Copy link
Author

Erykiusz commented Aug 22, 2024

When channels are detected they are all automatically merged to create model for the viewer and the output pdb file. If you would lower the sparsity you would get more channels that overlap, and if you would set it to 0, all the surface points of the molecule will be used as the end points of channels, resulting in many channels that highly overlap.

@jamesmkrieger
Copy link

ok, thanks

@karolamik13
Copy link
Owner

When channels are detected they are all automatically merged to create model for the viewer and the output pdb file. If you would lower the sparcity you would get more channels that overlap, and if you would set it to 0, all the surface points of the molecule will be used as the end points of channels, resulting in many channels that highly overlap.

This kind of information is very useful. At some point, we will have to include them somewhere. When the tool will be ready, I will prepare a tutorial similar to those:
http://www.bahargroup.org/prody/tutorials/
where we will have to show different cases and how different parameters change the outcome.
Later I will ask you to collect different commands somewhere in Jupyter Notebook file or so.

It would be very useful to be able to merge some selected channels (for example channel 1 and channel 9) to further compute values for them, residues that are forming the channel, etc. as for one merged channel.

@Erykiusz
Copy link
Author

Erykiusz commented Aug 25, 2024

New changes:
-runVmdScript replaced with getVmdModel, which requires only path to vmd.exe and atoms of the parsed protein. Returns protein model. (Example: model = getVmdModel(vmd_path, atoms))
-Added 2 new visualizer functions: showChannels and showCavities.
showChannels needs a list of channels to visualize, and optionally a protein model and surface. (Example: showChannels(channels, model=model, surface=surface))
showCavities needs surface of cavities (which is saved with protein surface in surface variable) to visualize and optionally can show protein surface with show_surface=True. (Example: showCavities(surface, show_surface=True))
-Replaced prints with LOGGER.info.
-Got rid of f-strings.
-calcChannels now has its base class with helper functions callled ChannelCalculator
-getChannelsParameters now returns also volumes of channels
-Better documentation
-Added calcChannelsMultipleFrames for computing channels from multiple frames. This is essentialy calcInteractionsMultipleFrames with slight modifications.

I didn't yet tested calcChannelsMultipleFrames with proper files so there might be errors.

@karolamik13 accessing the atoms of channels should be done to get artificial atoms making the path of the channels (hydrogen atoms from resuting pdb file) or atoms that make the surface of channels?

@karolamik13
Copy link
Owner

@Erykiusz "atoms that make the surface of channels" are more useful, but could we have both?

Under Lunux, vmd is usually here:
vmd_path = '/usr/local/bin/vmd' This is the default localization, but I think we can use "whereis vmd" or another command to check it if the one above is not correct. I am not sure, though, how to do it under Windows or Mac.

I tested different functions, and they are working well except for calcChannelsMultipleFrames() where I had this error:
_---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
Cell In[23], line 1
----> 1 channels2, surfaces2 = calcChannelsMultipleFrames(p2)

File ~/anaconda3/envs/prody/lib/python3.9/site-packages/ProDy-2.5.0-py3.9-linux-x86_64.egg/prody/proteins/interactions.py:4872, in calcChannelsMultipleFrames(atoms, trajectory, output_path, **kwargs)
4870 LOGGER.info('Model: {0}'.format(i+start_frame))
4871 atoms.setACSIndex(i+start_frame)
-> 4872 channels = calculator.calcChannels(atoms, output_path / "_{0}.pdb".format(i+start_frame), **kwargs)
4873 channels_all.append(channels)
4874 else:

AttributeError: 'ChannelCalculator' object has no attribute 'calcChannels'_

I am sending multi-model PDB and trajectory via e-mail, which you can use for tests.

@Erykiusz
Copy link
Author

Now it should be working fine

@karolamik13
Copy link
Owner

@Erykiusz

Yes, now multi-model PDB and trajectory analysis are working fine. Great job!
I am sending you the Jupyter Notebook file with my tests.

Several questions:
(1) Single PDB:

  • Can you have access to the dummy atoms that are forming the channels? (I think you are working on that)
    If we have access, we can apply:
    residues_forming_channel = atoms.select('same residue as exwithin 4 of ' +selection)
    and selection will be the coordinates of dummy atoms.
    That should be available for each channel among the detected ones.

  • Can we combine two channels into one and obtain the results?

(2) Multi-model PDB / trajectories:

  • How can we display the results? (visualization, volume for each channel).
  • Can we combine two or three channels to obtain the results?

After addressing those things, I will merge the pull request.
Thank you!

@Erykiusz
Copy link
Author

(1) Yes, this is now in progress. Both residues forming the channels and merging them are in my queue.
(2) Results can be displayed the same way as for the single pdb. To access the channels for specific frames/models we can simply write channels[n], where n is the index of a frame/model, because results are in a form of list. It is basically a list of lists. The same works for surfaces. The results can also be written in pdb form with output_path set not to none. The results are then saved as separate files for each frame.
I don't really understand what you mean with combining channels to obtain results in multi pdb/trajectories. Should it be the same as for single pdb?

@karolamik13
Copy link
Owner

Combining the channels: We may have two channels near each other, and we might want to join them, visualize them, and compute the volume and residues that are participating in the formation of that joint channel (=two channels or more, for example, channel[1] and channel[3]). Unless you think there is no point in doing that because each channel shows the whole pathway or for other reasons. For both single PDB and trajectory, I was thinking the same thing.

@Erykiusz
Copy link
Author

Ok, I will work on that

@jamesmkrieger
Copy link

I guess there should be some criteria that are different for combining channels in a trajectory e.g. if they are close in one frame then they could be combined in all frames. Maybe we end up with a channel that has two disconnected parts in some frames and that would be interesting to see.

@jamesmkrieger
Copy link

It could be nice to have a way to turn channels on and off in the viewer, so we could open a few of them and then focus on particular ones. It would also be great if we can open a few frames and turn them on and off to have everything in the same viewer to cross compare rather than having to open and close the viewers in between or open multiple instances.

Is it possible to continue typing in the terminal while a viewer is open to perform further analysis based on what we see and open other viewers?

Also, what quantitative measures do we have like width along the channel with some connection to lining residues and can we compare these across frames? Could we maybe make a plot of width near a particular residue over time for example?

@Erykiusz
Copy link
Author

Erykiusz commented Aug 26, 2024

I've added getChannelAtoms which returns an AtomGroup object of dummy atoms forming the channels. The user can also choose a 'resolution' which is basically a number of samples multipled by the length of the channel. The default value is 5 which is the same as for outputing pdb file. When calling getChannelAtoms we get an object that merges all the channels into one.
Example usage: channel_atoms = getChannelAtoms(channels)

Also, I don't really see the need for merging channels because the values from getChannelAtoms and getChannelParameters are from the list of channels anyway. If we would want to get values for specific channels we could just simply manipulate elements of the channel list. For example:
selected_channels = channels[1:4]

And then we could get the parameters and atoms making all the channels with:
lengths, bottlenecks, volumes = getChannelParameters(selected_channels)
selected_channels_atoms = getChannelAtoms(selected_channels)

We could also visualize only the channels of interest:
showChannels(selected_channels, model)

Another thing is that channels are saved as CubicSplines and merging them would result in very strange results. If the merging of channels would be necessery, I would think of a solution, but I think the method I described above should be enough, but correct me if I'm wrong.

I also changed getChannelsParameters to getChannelParameters.

When it comes to viewer, I didn't experiment with changing it while it is running and I don't know if it is possible. Opening multiple viewers is not possible right now.

We can compare the quantitive measures from getChannelParameters from different frames and for now it is an only option.

@jamesmkrieger
Copy link

Ok, makes sense. Thanks

@karolamik13
Copy link
Owner

I tested everything, and it works great!

Two suggestions:
(1) Can we add a function that will save all detected channels separately instead of together too?
channels, surface = calcChannels(atoms, output_path='channels_output.pdb')
for example by applying 'output_all'='channel' and then we will obtain channel_1.pdb, channel_2.pdb, etc.

(2) Can you create a function like getChannelAtoms() that will return protein + channel coordinates (or add a parameter to include it in getChannelAtoms())?
If you have protein+channel's atoms, you can use such command:
distance = 4
residues = prot_and_channels_atoms.select('same residue as exwithin '+str(distance)+' of resname FIL')
and you will have information about residues (from protein structure) that are participating in the formation of the channel.
The last thing that is needed.

@Erykiusz
Copy link
Author

I've added a parameter 'separate' to calcChannels and calcChannelsMultipleFrames that enables writing separate output files for each channel. Examples:
channels, surface = calcChannels(protein, output, separate=True)
all_channels, all_surfaces=calcChannelsMultipleFrames(multi, traj, output_path = output, separate=True)

Also getChannelAtoms now has a parameter 'protein' that when set to an AtomGroup object (parsed protein) will merge itsef with the channels. Example:
atoms_protein = getChannelAtoms(channels, protein)

@karolamik13
Copy link
Owner

karolamik13 commented Aug 27, 2024

Works great. We can also add a function to obtain residues that are forming the channel, but it can be done later.
Now everyone gets this by using:
p = parsePDB('1tqn.pdb')
atoms = p.select("protein")
channels, surface = calcChannels(atoms)

for channel[1]:
atoms_protein = getChannelAtoms(channels[1], atoms)
distance = 4
residues = atoms_protein.select('same residue as exwithin '+str(distance)+' of resname FIL')
list(zip(residues.select('name CA').getResnames(), residues.select('name CA').getResnums()))

Once the checks are done successfully (at least for Python 3.8 and higher), I will accept the pull request.

@jamesmkrieger
Copy link

Ideally we should remove the fstrings from interactions.py so that the python 2 import works too

@karolamik13
Copy link
Owner

Ideally we should remove the fstrings from interactions.py so that the python 2 import works too

Yes, you are right.

@Erykiusz
Copy link
Author

Are the f-strings in my code causing problems? Because there was only one f-string in checkAndImport, which I removed.

@karolamik13
Copy link
Owner

If you look here:
https://github.com/karolamik13/ProDy/actions/runs/10585767777/job/29333210140?pr=7

You will see that also that line is problematic:
s_tmp.set_state(*calculator.delete_simplices3d(coords, *s_tmp.get_state(), vdw_radii, r1, True))

and probably would work if you make it like the one below so that it would be compatible with Python 2.7.
state = calculator.delete_simplices3d(coords, *s_tmp.get_state())
s_tmp.set_state(state, vdw_radii, r1, True)

But we might have more of those in a code. It works for Python 3.8 and higher, so I am happy with the code.

@jamesmkrieger maybe it would be a good time to finally drop Python 2.7?
If not then we will look later at that to fix it.

@karolamik13 karolamik13 merged commit 7464d7b into karolamik13:main Aug 28, 2024
4 of 5 checks passed
@jamesmkrieger
Copy link

We would have to change how we build the website, but yes, it would be great if we could

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants