Skip to content

Commit

Permalink
Merge pull request #10 from dwhswenson/0.1.1
Browse files Browse the repository at this point in the history
v0.1.1
  • Loading branch information
dwhswenson authored Oct 8, 2017
2 parents 6f8b1ae + e03134e commit 9a7884c
Show file tree
Hide file tree
Showing 11 changed files with 87 additions and 59 deletions.
25 changes: 25 additions & 0 deletions .codeclimate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
engines:
radon:
enabled: true
exclude_paths:
- "*/tests/"
config:
threshold: "C"

fixme:
enabled: true
issue_override:
severity: info
exclude_paths:
- "**pdb"

duplication:
enabled: true
config:
languages:
python:
mass_threshold: 35

ratings:
paths:
- "**py"
16 changes: 12 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
language: python

branches:
only:
- master
- stable

python:
- "2.7"
- "3.4"
Expand All @@ -8,8 +13,11 @@ python:
#- "3.7-dev" # need to do custom requirements install for this

env:
- MDTRAJ="release"
- MDTRAJ="dev"
global:
- CODECLIMATE="" # add this later
matrix:
- MDTRAJ="release"
- MDTRAJ="dev"

matrix:
exclude: # don't run MDTRAJ dev for everything
Expand All @@ -25,8 +33,8 @@ install:
- pip list

script:
- py.test -vv --cov=contact_map
- py.test -vv --cov=contact_map --cov-report xml:cov.xml

after_success:
- coveralls

- python-codacy-coverage -r cov.xml
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
[![Linux Build Status](https://travis-ci.org/dwhswenson/contact_map.svg?branch=master)](https://travis-ci.org/dwhswenson/contact_map)
[![Windows Build status](https://ci.appveyor.com/api/projects/status/em3fo96sjrg2vmcc/branch/master?svg=true)](https://ci.appveyor.com/project/dwhswenson/contact-map/branch/master)
[![Coverage Status](https://coveralls.io/repos/github/dwhswenson/contact_map/badge.svg?branch=master)](https://coveralls.io/github/dwhswenson/contact_map?branch=master)
[![codebeat badge](https://codebeat.co/badges/c7fb604a-35a8-4ccf-afea-18d6bd494726)](https://codebeat.co/projects/github-com-dwhswenson-contact_map-master)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/f7f3cf53698e4655ac8895f13fa5dea6)](https://www.codacy.com/app/dwhswenson/contact_map?utm_source=github.com&utm_medium=referral&utm_content=dwhswenson/contact_map&utm_campaign=Badge_Grade)
[![Code Climate](https://codeclimate.com/github/dwhswenson/contact_map/badges/gpa.svg)](https://codeclimate.com/github/dwhswenson/contact_map)

# Contact Maps

Expand Down
2 changes: 2 additions & 0 deletions bandit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
exclude_dirs:
- /tests
2 changes: 1 addition & 1 deletion ci/conda-recipe/meta.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package:
name: contact_map
version: "0.1.0"
version: "0.1.1"

source:
path: ../../
Expand Down
2 changes: 2 additions & 0 deletions ci/pip-install/install.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#!/usr/bin/env bash

pip install --upgrade pip
pip install cython # may be required for numpy override?
pip install --upgrade --force-reinstall numpy # override Travis numpy
Expand Down
1 change: 1 addition & 0 deletions ci/pip-install/testing_requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pytest
pytest-cov
python-coveralls
codacy-coverage
50 changes: 21 additions & 29 deletions contact_map/contact_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ def residue_neighborhood(residue, n=1):
# good, and it only gets run once per residue
return [idx for idx in neighborhood if idx in chain]

def _residue_and_index(residue, topology):
res = residue
try:
res_idx = res.index
except AttributeError:
res_idx = residue
res = topology.residue(res_idx)
return (res, res_idx)


class ContactCount(object):
def __init__(self, counter, object_f, n_x, n_y):
Expand Down Expand Up @@ -181,12 +190,7 @@ def residue_ignore_atom_idxs(self):
return result

def most_common_atoms_for_residue(self, residue):
try:
residue_idx = residue.index
except AttributeError:
residue_idx = residue
residue = self.topology.residue(residue_idx)

residue = _residue_and_index(residue, self.topology)[0]
residue_atoms = set(atom.index for atom in residue.atoms)
results = []
for contact in self.atom_contacts.most_common_idx():
Expand All @@ -199,24 +203,14 @@ def most_common_atoms_for_residue(self, residue):
return results

def most_common_atoms_for_contact(self, contact_pair):
contact_pair = frozenset(contact_pair)
res_A = list(contact_pair)[0]
res_B = list(contact_pair)[1]
try:
res_A_idx = res_A.index
except AttributeError:
res_A_idx = res_A
res_A = self.topology.residue(res_A_idx)
try:
res_B_idx = res_B.index
except AttributeError:
res_B_idx = res_B
res_B = self.topology.residue(res_B_idx)
atom_idxs_A = set(atom.index for atom in res_A.atoms)
atom_idxs_B = set(atom.index for atom in res_B.atoms)
contact_pair = list(contact_pair)
res_1 = _residue_and_index(contact_pair[0], self.topology)[0]
res_2 = _residue_and_index(contact_pair[1], self.topology)[0]
atom_idxs_1 = set(atom.index for atom in res_1.atoms)
atom_idxs_2 = set(atom.index for atom in res_2.atoms)
all_atom_pairs = [
frozenset(pair)
for pair in itertools.product(atom_idxs_A, atom_idxs_B)
for pair in itertools.product(atom_idxs_1, atom_idxs_2)
]
result = [([self.topology.atom(idx) for idx in contact[0]], contact[1])
for contact in self.atom_contacts.most_common_idx()
Expand Down Expand Up @@ -256,14 +250,14 @@ def contact_map(self, trajectory, frame_number, residue_query_atom_idxs,
contact_neighbors = contact_neighbors & self._haystack
# frozenset is unique key independent of order
# local_pairs = set(frozenset((atom_idx, neighb))
# for neighb in contact_neighbors)
# for neighb in contact_neighbors)
local_pairs = set(map(
frozenset,
itertools.product([atom_idx], contact_neighbors)
))
contact_pairs |= local_pairs
# contact_pairs |= set(frozenset((atom_idx, neighb))
# for neighb in contact_neighbors)
# for neighb in contact_neighbors)
local_residue_partners = set(self._atom_idx_to_residue_idx[a]
for a in contact_neighbors)
local_res_pairs = set(map(
Expand All @@ -274,8 +268,8 @@ def contact_map(self, trajectory, frame_number, residue_query_atom_idxs,

atom_contacts = collections.Counter(contact_pairs)
# residue_pairs = set(
# frozenset(self._atom_idx_to_residue_idx[aa] for aa in pair)
# for pair in contact_pairs
# frozenset(self._atom_idx_to_residue_idx[aa] for aa in pair)
# for pair in contact_pairs
# )
residue_contacts = collections.Counter(residue_pairs)
return (atom_contacts, residue_contacts)
Expand Down Expand Up @@ -359,9 +353,7 @@ def _build_contact_map(self):
# TODO: this whole thing should be cleaned up and should replace
# MDTraj's really slow old computer_contacts by using MDTraj's new
# neighborlists (unless the MDTraj people do that first).
topology = self.topology
trajectory = self.trajectory
cutoff = self.cutoff
self._atom_contacts_count = collections.Counter([])
self._residue_contacts_count = collections.Counter([])

Expand Down Expand Up @@ -429,7 +421,7 @@ def __init__(self, positive, negative):
def __sub__(self, other):
raise NotImplementedError

def contact_map(self, *args, **kwargs):
def contact_map(self, *args, **kwargs): #pylint: disable=W0221
raise NotImplementedError

@property
Expand Down
2 changes: 2 additions & 0 deletions contact_map/min_dist.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import collections
import itertools
import mdtraj as md

class NearestAtoms(object):
Expand Down
37 changes: 15 additions & 22 deletions contact_map/tests/test_contact_map.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import os
import collections
import itertools
import pytest
import numpy as np
from numpy.testing import assert_array_equal
import mdtraj as md

# pylint: disable=wildcard-import, missing-docstring, protected-access
# pylint: disable=attribute-defined-outside-init, invalid-name, no-self-use
# pylint: disable=wrong-import-order, unused-wildcard-import

from .utils import *

# stuff to be testing in this file
from contact_map.contact_map import *


traj = md.load(test_file("trajectory.pdb"))

traj_atom_contact_count = {
Expand Down Expand Up @@ -39,6 +44,10 @@
def counter_of_inner_list(ll):
return collections.Counter([frozenset(i) for i in ll])

def check_most_common_order(most_common):
for i in range(len(most_common) - 1):
assert most_common[i][1] >= most_common[i+1][1]

def test_residue_neighborhood():
top = traj.topology
residues = list(top.residues)
Expand Down Expand Up @@ -248,9 +257,7 @@ def test_most_common_atoms_for_residue(self, select_by):
raise RuntimeError("This should not happen")
# call both by residue and residue number
most_common_2 = self.map.most_common_atoms_for_residue(res_2)
# check order is correct
for i in range(len(most_common_2) - 1):
assert most_common_2[i][1] >= most_common_2[i+1][1]
check_most_common_order(most_common_2)

most_common_numbers_2 = {frozenset([k[0].index, k[1].index]): v
for (k, v) in most_common_2}
Expand Down Expand Up @@ -278,11 +285,7 @@ def test_most_common_atoms_for_contact(self, select_by):
raise RuntimeError("This should not happen")

most_common_2_3 = self.map.most_common_atoms_for_contact(pair)

# check order is correct
for i in range(len(most_common_2_3) - 1):
assert most_common_2_3[i][1] >= most_common_2_3[i+1][1]

check_most_common_order(most_common_2_3)
most_common_2_3_frozenset = [(frozenset(ll[0]), ll[1])
for ll in most_common_2_3]

Expand Down Expand Up @@ -371,42 +374,32 @@ def test_most_common(self, obj_type):
most_common = contacts.most_common()
cleaned = [(frozenset(ll[0]), ll[1]) for ll in most_common]

# check order
for i in range(len(most_common) - 1):
assert most_common[i][1] >= most_common[i+1][1]

# check contents
check_most_common_order(most_common)
assert set(cleaned) == set(expected)

@pytest.mark.parametrize("obj_type", ['atom', 'res'])
def test_most_common_with_object(self, obj_type):
top = self.topology
if obj_type == 'atom':
source_expected = traj_atom_contact_count
contacts = self.map.atom_contacts
obj = top.atom(4)
expected = [(frozenset([obj, top.atom(6)]), 1.0),
(frozenset([obj, top.atom(1)]), 0.8),
(frozenset([obj, top.atom(7)]), 0.4),
(frozenset([obj, top.atom(8)]), 0.2)]
elif obj_type == 'res':
source_expected = traj_residue_contact_count
contacts = self.map.residue_contacts
obj = self.topology.residue(2)
expected = [(frozenset([obj, top.residue(0)]), 1.0),
(frozenset([obj, top.residue(3)]), 1.0),
(frozenset([obj, top.residue(4)]), 0.2)]
else:
raise RuntimeError("This shouldn't happen")

most_common = contacts.most_common(obj)
cleaned = [(frozenset(ll[0]), ll[1]) for ll in most_common]

# check order
for i in range(len(most_common) - 1):
assert most_common[i][1] >= most_common[i+1][1]

# check contents
check_most_common_order(most_common)
assert set(cleaned) == set(expected)

@pytest.mark.parametrize("obj_type", ['atom', 'res'])
Expand Down
6 changes: 3 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
"""
#from distutils.sysconfig import get_config_var
# from distutils.core import setup, Extension
from setuptools import setup, Extension
from setuptools import setup
# import numpy
# import glob
import os
import subprocess

##########################
VERSION = "0.1.0"
ISRELEASED = False
VERSION = "0.1.1"
ISRELEASED = True
__version__ = VERSION
PACKAGE_VERSION = VERSION
REQUIREMENTS=['future', 'numpy', 'mdtraj', 'scipy', 'pandas']
Expand Down

0 comments on commit 9a7884c

Please sign in to comment.