Desenvolvendo um banco de dados de bioinformática para pesquisa de ligações dissulfeto
Publicados: 2022-03-11O banco de dados de bioinformática do Protein Data Bank (PDB) é o maior repositório do mundo de estruturas de proteínas, ácidos nucleicos e montagens complexas determinadas experimentalmente. Todos os dados são coletados usando métodos experimentais como raios-X, espectroscopia, cristalografia, RMN, etc.
Este artigo explica como extrair, filtrar e limpar dados do PDB. Isso, por sua vez, permite o tipo de análise explicado no artigo Ocorrência de ligações dissulfeto de proteínas em diferentes domínios da vida: uma comparação de proteínas do Protein Data Bank, publicado em Protein Engineering, Design and Selection , Volume 27, Issue 3, 1 de março de 2014, pp. 65–72.
O PDB tem muitas estruturas repetidas com diferentes resoluções, métodos, mutações, etc. Fazer um experimento com proteínas iguais ou semelhantes pode produzir viés em qualquer análise de grupo, então precisaremos escolher a estrutura correta entre qualquer conjunto de duplicatas . Para isso, precisamos usar um conjunto de proteínas não redundantes (NR).
Para fins de normalização, recomendo baixar o dicionário de compostos químicos para importar nomes de átomos em um banco de dados que usa 3NF ou usa um esquema em estrela e modelagem dimensional. (Também usei o DSSP para ajudar a eliminar estruturas problemáticas. Não abordarei isso neste artigo, mas observe que não usei nenhum outro recurso do DSSP.)
Os dados usados nesta pesquisa contêm proteínas de unidade única que contêm pelo menos uma ligação dissulfeto retirada de diferentes espécies. Para realizar uma análise, todas as ligações dissulfeto são primeiramente classificadas como consecutivas ou não consecutivas, por domínio (arqueia, procarioto, viral, eucarioto ou outro) e também por comprimento.
Fonte: Protein Engineering, Design and Selection , conforme mencionado no início deste artigo.
Saída
Para estar pronto para entrada em R, SPSS ou alguma outra ferramenta, um analista precisará que os dados estejam em uma tabela de banco de dados com esta estrutura:
Coluna | Tipo | Descrição |
---|---|---|
code | character(4) | ID do experimento (alfanumérico, não diferencia maiúsculas de minúsculas e não pode começar com zero) |
title | character varying(1000) | Título do experimento, para referência (o campo também pode ser em formato de texto) |
ss_bonds | integer | Número de ligações dissulfeto na cadeia escolhida |
ssbonds_overlap | integer | Número de ligações dissulfeto sobrepostas |
intra_count | integer | Número de ligações feitas dentro da mesma cadeia |
sci_name_src | character varying(5000) | Nome científico do organismo do qual a sequência é retirada |
tax_path | character varying | Caminho na árvore de classificação de Lineu |
src_class | character varying(20) | Classe de organismo de nível superior (eucarioto, procarionte, vírus, archaea, outro) |
has_reactives7 | boolean | Verdadeiro se e somente se a sequência contiver centros reativos |
len_class7 | integer | Comprimento da sequência no conjunto 7 (definido com valor p 10e-7 calculado por explosão) |
Materiais e métodos
Para atingir esse objetivo, o primeiro passo é coletar dados do rcsb.org. Esse site contém estruturas PDB de experimentos para download em vários formatos.
Embora os dados sejam armazenados em vários formatos, neste exemplo, apenas o formato textual delimitado por espaço fixo (PDB) formatado será usado. Uma alternativa ao formato textual PDB é sua versão XML, PDBML, mas às vezes contém entradas de nomenclatura de posição de átomo malformadas, o que pode causar problemas para análise de dados. O mmCIF mais antigo e outros formatos também podem estar disponíveis, mas não serão explicados neste artigo.
O formato PDB
O formato PDB é um formato textual fragmentado de largura fixa que pode ser facilmente analisado por consultas SQL, plugins Java ou módulos Perl, por exemplo. Cada tipo de dados no contêiner de arquivo é representado como uma linha que começa com a tag apropriada—vamos passar por cada tipo de tag nas subseções a seguir. O comprimento da linha é menor ou igual a 80 caracteres, onde uma tag leva seis ou menos caracteres mais um ou mais espaços que juntos ocupam oito bytes. Há também casos sem espaços entre tags e dados, geralmente para tags CONECT
.
TITLE
A etiqueta TITLE
marca uma linha como sendo (parte do) título do experimento, contendo o nome da molécula e outros dados relevantes como a inserção, mutação ou deleção de um aminoácido específico.
12345678901234567890123456789012345678901234567890123456789012345678901234567890 TITLE A TWO DISULFIDE DERIVATIVE OF CHARYBDOTOXIN WITH DISULFIDE TITLE 2 13-33 REPLACED BY TWO ALPHA-AMINOBUTYRIC ACIDS, NMR, 30 TITLE 3 STRUCTURES
No caso de haver várias linhas para um registro TITLE
, então o título deve ser concatenado, ordenando por um número de continuação, que é colocado, alinhado à direita, nos bytes 9 e 10 (dependendo do número dessas linhas).
ATOM
Os dados armazenados nas linhas ATOM
são dados de coordenadas para cada átomo em um experimento. Às vezes, um experimento tem inserções, mutações, locais alternativos ou vários modelos. Isso resulta na repetição do mesmo átomo várias vezes. A escolha dos átomos certos será explicada mais adiante.
12345678901234567890123456789012345678901234567890123456789012345678901234567890 ATOM 390 N GLY A 26 -1.120 -2.842 4.624 1.00 0.00 N ATOM 391 CA GLY A 26 -0.334 -2.509 3.469 1.00 0.00 C ATOM 392 C GLY A 26 0.682 -1.548 3.972 1.00 0.00 C ATOM 393 O GLY A 26 0.420 -0.786 4.898 1.00 0.00 O ATOM 394 H GLY A 26 -0.832 -2.438 5.489 1.00 0.00 H ATOM 395 HA2 GLY A 26 0.163 -3.399 3.111 1.00 0.00 H ATOM 396 HA3 GLY A 26 -0.955 -2.006 2.739 1.00 0.00 H
O exemplo acima é retirado do experimento 1BAH
. A primeira coluna marca o tipo de registro e a segunda coluna é o número de série do átomo. Cada átomo em uma estrutura tem seu próprio número de série.
Ao lado do número de série há o rótulo de posição do átomo, que ocupa quatro bytes. A partir dessa posição do átomo, é possível extrair o símbolo químico do elemento, que nem sempre está presente nos dados do registro em sua própria coluna separada.
Após o nome do átomo, há um código residual de três letras. No caso das proteínas, esse resíduo corresponde a um aminoácido. Em seguida, a cadeia é codificada com uma letra. Por cadeia , queremos dizer uma única cadeia de aminoácidos, com ou sem lacunas, embora às vezes os ligantes possam ser atribuídos a uma cadeia; este caso é detectável através de lacunas muito grandes em uma sequência de aminoácidos, que está na próxima coluna. Às vezes, a mesma estrutura pode ser escaneada com mutações incluídas, caso em que o código de inserção está disponível em uma coluna extra após a coluna de sequência. O código de inserção contém uma letra para ajudar a distinguir qual resíduo é afetado.
As próximas três colunas são as coordenadas espaciais de cada átomo, medidas em Angstroms (Å). Ao lado dessas coordenadas está a coluna de ocupação, que diz qual é a probabilidade de o átomo estar naquele local, na escala usual de zero a um.
A penúltima coluna é o fator de temperatura, que carrega informações sobre a desordem no cristal, medida em Ų. Um valor maior que 60Ų significa desordem, enquanto um valor menor que 30Ų significa confiança. Nem sempre está presente em arquivos PDB porque depende do método experimental.
As próximas colunas — símbolo e carga — geralmente estão ausentes. O símbolo químico pode ser obtido na coluna de posição do átomo, como mencionamos acima. Quando a carga está presente, ela é sufixada ao símbolo como um número inteiro seguido por +
ou -
, por exemplo, N1+
.
TER
Isso marca o fim da cadeia. Mesmo sem essa linha, é fácil distinguir onde termina uma cadeia. Assim, muitas vezes a linha TER
está ausente.
MODEL
e ENDMDL
Uma linha MODEL
marca onde o modelo de uma estrutura começa e contém o número de série do modelo.
Depois de todas as linhas atômicas nesse modelo, ele termina com uma linha ENDMDL
.
SSBOND
Essas linhas contêm ligações dissulfeto entre aminoácidos cisteína. As ligações dissulfeto podem estar presentes em outros tipos de resíduos, mas neste artigo serão analisados apenas aminoácidos, portanto apenas a cisteína está incluída. O exemplo a seguir é do experimento com o código 132L
:
12345678901234567890123456789012345678901234567890123456789012345678901234567890 SSBOND 1 CYS A 6 CYS A 127 1555 1555 2.01 SSBOND 2 CYS A 30 CYS A 115 1555 1555 2.05 SSBOND 3 CYS A 64 CYS A 80 1555 1555 2.02 SSBOND 4 CYS A 76 CYS A 94 1555 1555 2.02
Neste exemplo, há quatro ligações dissulfeto marcadas no arquivo com seu número de sequência na segunda coluna. Todas essas ligações utilizam cisteína (colunas 3 e 6), e todas estão presentes na cadeia A
(colunas 4 e 7). Após cada cadeia há um número de sequência de resíduos indicando a posição da ligação na cadeia peptídica. Os códigos de inserção estão ao lado de cada sequência de resíduos, mas neste exemplo eles não estão presentes porque não havia nenhum aminoácido inserido nessa região. As duas colunas anteriores à última são reservadas para operações de simetria, e a última coluna é a distância entre os átomos de enxofre, medida em Å.
Vamos dar um momento para contextualizar esses dados.
As fotos abaixo, tiradas usando o visualizador rcsb.org NGL, mostram a estrutura do experimento 132L
. Em particular, eles mostram uma proteína sem ligantes. A primeira foto usa uma representação em bastão, com coloração CPK mostrando enxofres e suas ligações em amarelo. As conexões de enxofre em forma de V representam conexões de metionina, enquanto as conexões em forma de Z são ligações dissulfeto entre cisteínas.
Na próxima figura, um método simplificado de visualização de proteínas chamado visualização de backbone é mostrado colorido por aminoácidos, onde as cisteínas são amarelas. Ela representa a mesma proteína, com sua cadeia lateral excluída e apenas parte de seu grupo peptídico incluído – neste caso, a cadeia principal da proteína. É feito de três átomos: N-terminal, C-alfa e C-terminal. Esta imagem não mostra ligações dissulfeto, mas é simplificada para mostrar o arranjo espacial da proteína:
Os tubos são criados juntando átomos ligados a peptídeos com um átomo C-alfa. A cor da cisteína é igual à cor do enxofre no método de coloração CPK. Quando os cistenos se aproximam o suficiente, seus enxofres criam ligações dissulfeto, e isso fortalece a estrutura. Caso contrário, essa proteína se ligaria demais e sua estrutura seria menos estável em temperaturas mais altas.
CONECT
Esses registros são usados para marcar conexões entre átomos. Às vezes, essas tags não estão presentes, enquanto outras vezes todos os dados são preenchidos. No caso de análise de ligações dissulfeto, essa parte pode ser útil, mas não é necessária. Isso porque, neste projeto, os títulos não etiquetados são adicionados medindo as distâncias, então isso seria uma sobrecarga, e também tem que ser verificado.
SOURCE
Esses registros contêm informações sobre o organismo de origem do qual a molécula foi extraída. Eles contêm subregistros para facilitar a localização na taxonomia e têm a mesma estrutura de várias linhas que vimos com os registros de título.
SOURCE MOL_ID: 1; SOURCE 2 ORGANISM_SCIENTIFIC: ANOPHELES GAMBIAE; SOURCE 3 ORGANISM_COMMON: AFRICAN MALARIA MOSQUITO; SOURCE 4 ORGANISM_TAXID: 7165; SOURCE 5 GENE: GST1-6; SOURCE 6 EXPRESSION_SYSTEM: ESCHERICHIA COLI; SOURCE 7 EXPRESSION_SYSTEM_TAXID: 562; SOURCE 8 EXPRESSION_SYSTEM_STRAIN: BL21(DE3)PLYSS; SOURCE 9 EXPRESSION_SYSTEM_VECTOR_TYPE: PLASMID; SOURCE 10 EXPRESSION_SYSTEM_PLASMID: PXAGGST1-6
Formato NR
Esta é uma lista de conjuntos PDB de cadeia não redundante (NR). Seus instantâneos podem ser encontrados em ftp.ncbi.nih.gov/mmdb/nrtable/. Seu objetivo é evitar vieses desnecessários causados pela similaridade de proteínas. NR tem três conjuntos com diferentes níveis de valor p de identidade criados pela comparação de todas as estruturas PDB. O resultado é adicionado a arquivos textuais que serão explicados posteriormente. Nem todas as colunas são necessárias para este projeto, portanto, apenas as importantes serão explicadas.
As duas primeiras colunas contêm o código exclusivo do experimento PDB e o identificador da cadeia, conforme explicado para os registros ATOM
acima. As colunas 6, 9 e C contêm informações sobre a representatividade do valor p, que é o nível de similaridade das sequências calculadas pelo BLAST. Se esse valor for zero, então não é aceito fazer parte de um conjunto; se o valor for 1, então é. As colunas mencionadas representam a aceitação de conjuntos com valores-p de corte de 10e-7, 10e-40 e 10e-80, respectivamente. Apenas conjuntos com um valor de corte de p de 10e-7 serão usados para análise.
A última coluna contém informações sobre a aceitabilidade de uma estrutura, onde a
é aceitável e n
não.
#--------------------------------------------------------------------------------------------------------------------------- # 1 2 3 4 5 6 7 8 9 ABCDEFGHIJKLMNOPQ #--------------------------------------------------------------------------------------------------------------------------- 3F8V A 69715 1 1 1 1 1 1 1 1 1 9427 1 1 0.00 0.00 0.00 0.00 1.08 1 6 5 164 X a 3DKE X 68132 1 2 0 1 2 0 1 2 0 39139 1 1 0.00 0.00 0.00 0.00 1.25 1 11 7 164 X a 3HH3 A 77317 1 3 0 1 3 0 1 3 0 90 1 0 0.00 0.00 0.00 0.00 1.25 1 5 4 164 X a 3HH5 A 77319 1 4 0 1 4 0 1 4 0 90 2 0 0.00 0.00 0.00 0.00 1.25 1 4 4 164 X a
Construção de banco de dados e dados de análise
Agora que temos uma ideia do que estamos lidando e do que precisamos fazer, vamos começar.
Baixando dados
Todos os dados para esta análise podem ser encontrados nestes três endereços:
- ftp.wwpdb.org/pub/pdb/data/structures/divided/pdb/
- ftp.ncbi.nih.gov/mmdb/nrtable/
- ftp.ncbi.nih.gov/pub/taxonomy/taxdmp.zip
Os dois primeiros links contêm uma lista de arquivos. O arquivo mais recente de cada um deve ser usado para evitar problemas decorrentes da falta de resolução ou qualidade. O terceiro link contém diretamente o arquivo de taxonomia mais recente.
Dados de análise
Normalmente, a análise de arquivos PDB é feita por plugins ou módulos em Java, Perl ou Python. No caso desta pesquisa, escrevi um aplicativo Perl personalizado sem usar um módulo de análise de PDB pré-escrito. A razão para isso é ao analisar uma grande quantidade de dados, na minha experiência, o problema mais comum com o uso de dados experimentais são erros nos dados. Às vezes há erros com coordenadas, distâncias, comprimentos de linha, comentários em lugares onde não deveriam estar, etc.
A maneira mais eficaz de lidar com isso é armazenar inicialmente tudo no banco de dados como texto bruto. Os analisadores comuns são escritos para lidar com dados ideais que estão em total conformidade com as especificações. Mas, na prática, os dados não são ideais, e isso será explicado na seção de filtragem, onde você encontrará o script de importação Perl.
Construção de banco de dados
Ao construir o banco de dados, observe que esse banco de dados é construído para processar dados. A análise posterior será feita em SPSS ou R. Para nossos propósitos aqui é recomendado usar PostgreSQL com pelo menos a versão 8.4.
A estrutura da tabela é copiada diretamente dos arquivos baixados com apenas algumas pequenas alterações. Nesse caso, o número de registros é muito pequeno para valer a pena gastar nosso tempo na normalização. Conforme mencionado, esse banco de dados é de uso único: essas tabelas não são criadas para serem atendidas em um site — elas estão lá apenas para processar dados. Uma vez terminado, eles podem ser descartados ou copiados como dados suplementares, talvez para repetir o processo por algum outro pesquisador.
Neste caso, o resultado final será uma tabela que pode ser exportada para um arquivo para uso com alguma ferramenta estatística como SPSS ou R.
Tabelas
A extração de dados dos registros ATOM
deve ser conectada aos registros HEADER
ou TITLE
. A hierarquia de dados é explicada na figura abaixo.
Como esta figura é uma representação simplificada de um banco de dados na terceira forma normal (3NF), para nossos propósitos ela contém muita sobrecarga. O motivo: para calcular a distância entre os átomos para a detecção de ligações dissulfeto, precisaríamos fazer junções. Nesse caso, teríamos uma tabela unida a si mesma duas vezes, e também unida a uma estrutura secundária e primária duas vezes cada, o que é um processo muito lento. Como nem toda análise precisa de informações de estrutura secundária, outro esquema é proposto caso você precise reutilizar dados ou analisar maiores quantidades de ligações dissulfeto:
As ligações dissulfeto não são tão frequentes quanto outras ligações covalentes, portanto, um modelo de armazém não é necessário, embora possa ser usado. O esquema em estrela e a modelagem dimensional abaixo levarão muito tempo para serem desenvolvidos e tornarão as consultas mais complexas:
Nos casos em que todos os títulos precisam ser processados, recomendo o esquema em estrela.
(Caso contrário não é necessário, porque as ligações dissulfeto não são tão comuns quanto outras ligações. uma tabela não normalizada, por isso não é retratada aqui.)
O número total esperado de todas as ligações covalentes é pelo menos o dobro do número de átomos na estrutura terciária e, nesse caso, a 3NF seria muito lenta, portanto, a desnormalização usando a forma de esquema em estrela é necessária. Nesse esquema, algumas tabelas têm duas verificações de chave estrangeira, e isso ocorre porque um vínculo é criado entre dois átomos, portanto, cada átomo precisa ter seu próprio primary_structure_id
, atom_name_id
e residue_id
.
Existem duas maneiras de preencher a tabela de dimensões d_atom_name
: a partir de dados e de outra fonte, o dicionário de componentes químicos que mencionei anteriormente. Seu formato é semelhante ao formato PDB: Somente as linhas RESIDUE
e CONECT
são úteis. Isso ocorre porque a primeira coluna de RESIDUE
contém um código de três letras de resíduo e CONECT
contém o nome do átomo e suas conexões, que também são nomes de átomos. Assim, a partir deste arquivo, podemos analisar todos os nomes de átomos e incluí-los em nosso banco de dados, embora eu recomende que você permita a possibilidade do banco de dados conter nomes de átomos não listados.
RESIDUE PRO 17 CONECT N 3 CA CD H CONECT CA 4 NC CB HA CONECT C 3 CA O OXT CONECT O 1 C CONECT CB 4 CA CG HB2 HB3 CONECT CG 4 CB CD HG2 HG3 CONECT CD 4 N CG HD2 HD3 CONECT OXT 2 C HXT CONECT H 1 N CONECT HA 1 CA CONECT HB2 1 CB CONECT HB3 1 CB CONECT HG2 1 CG CONECT HG3 1 CG CONECT HD2 1 CD CONECT HD3 1 CD CONECT HXT 1 OXT END HET PRO 17 HETNAM PRO PROLINE FORMUL PRO C5 H9 N1 O2
Neste projeto, a velocidade de codificação é mais relevante do que a velocidade de execução e consumo de armazenamento. Decidi não normalizar—afinal, nosso objetivo é gerar uma tabela com as colunas mencionadas na introdução.
Nesta parte, apenas as tabelas mais importantes serão explicadas.
As principais tabelas são:
-
proteins
: Tabela com nomes e códigos de experimentos. -
ps
: tabela de estrutura primária que conterásequence
,chain_id
ecode
. -
ts
: Tabela contendo estrutura terciária/quaternária extraída de dados brutos e transformada em formato de registroATOM
. Isso será usado como uma tabela de preparação e pode ser descartado após a extração. Os ligantes são excluídos. -
sources
: A lista de organismos dos quais os dados experimentais foram derivados. -
tax_names
,taxonomy_path
,taxonomy_paths
: nomes de taxonomia Linnean do banco de dados de taxonomia NCBI, usados para obter caminhos de taxonomia de organismos listados emsources
. -
nr
: Lista de proteínas não redundantes NCBI extraídas do conjunto NR. -
pdb_ssbond
: Lista de ligações dissulfeto em um determinado arquivo PDB.
Filtrando e Processando Dados
Os dados são recuperados de instantâneos do repositório RCSB PDB.
Cada arquivo é importado para uma única tabela raw_pdb
em nosso banco de dados PostgreSQL usando um script Perl. O script usa transações de 10.000 inserções por bloco.
A estrutura do raw_pdb
é esta:
Coluna | Tipo | Modificadores |
---|---|---|
código | caractere variando (20) | não nulo |
núm_linha | inteiro | não nulo |
linha_cont | caractere variando (80) | não nulo |
O script de importação se parece com isso:
#!/usr/bin/perl -w use FindBin '$Bin'; use DBI; $dbName = 'bioinf'; $dbLogin = 'ezop'; $dbPass = 'XYZ'; $conn = DBI->connect("DBI:Pg:database=$dbName;host=localhost", "$dbLogin", "$dbPass", {'RaiseError' => 1, 'AutoCommit' => 0}); die "./pdb_lines_unos.pl <table> <file>" if not defined($ARGV[0]); $recordCount = 0; $table = $ARGV[0]; $fName = $ARGV[1]; open F, "zcat $fName|"; while (<F>) { chomp; $linija = $_; $recordCount += 1; $sql = "insert into $table (code, line_num, line_cont) values (?, ?, ?)"; $conn->do($sql, undef, $fName, $recordCount, $linija); $conn->commit() if ($recordCount%10000 == 0); } close F; $conn->commit(); 1;
Depois que as linhas são importadas, elas são analisadas usando funções que definiremos abaixo.

A partir dos dados raw_pdb
, geramos as tabelas ts
, ps
, proteins
, sources
, sources_organela
e ss_bond
analisando os registros correspondentes.
A tabela ps
tem três colunas importantes: chain
, length
e sequence
. A sequência de proteínas é gerada usando átomos C-alfa para cada cadeia e para cada resíduo ordenado por sequência de resíduos, tomando apenas a primeira inserção e a primeira localização alternativa. chain
é retirado da coluna TS.chain
e length
é simplesmente o comprimento pré-calculado da string de sequence
. Como este artigo se destina a analisar apenas cadeias simples e conexões intracadeias, as proteínas de cadeia múltipla são ignoradas em nossa análise aqui.
Nos registros SSBOND
, todas as ligações dissulfeto são armazenadas na tabela pdb_ssbond
, que herda da tabela pdb_ssbond_extended
. pdb_ssbond
fica assim:
Coluna | Tipo | Anulável | Predefinição | Descrição |
---|---|---|---|---|
identificação | inteiro | não nulo | nextval('pdb_ssbond_id_seq'::regclass) | |
código | personagem(4) | código de quatro letras | ||
ser_num | inteiro | número de série do ssbond | ||
resíduo1 | personagem(3) | primeiro resíduo na ligação | ||
chain_id1 | caractere(1) | primeira cadeia em ligação | ||
res_seq1 | inteiro | número sequencial do primeiro resíduo | ||
i_code1 | caractere(1) | código de inserção do primeiro resíduo | ||
resíduo2 | personagem(3) | segundo resíduo em ligação | ||
chain_id2 | caractere(1) | segunda cadeia em ligação | ||
res_seq2 | inteiro | número sequencial do segundo resíduo | ||
i_code2 | caractere(1) | código de inserção do segundo resíduo | ||
sim1 | personagem(6) | primeiro operador de simetria | ||
sim2 | personagem(6) | segundo operador de simetria | ||
distância | numérico(5,2) | distância entre átomos | ||
é_reativo | boleano | não nulo | falso | marca para reatividade (a ser definida) |
é_consecutivo | boleano | não nulo | verdadeiro | marca para títulos consecutivos (a definir) |
representante7 | boleano | não nulo | falso | marca para estruturas set-7 (a ser definida) |
rep40 | boleano | não nulo | falso | marca para estruturas set-40 (a definir) |
rep80 | boleano | não nulo | falso | marca para estruturas set-80 (a definir) |
is_from_pdb | boleano | verdadeiro | é retirado do PDB como fonte (a ser definido) |
Eu também adicionei esses índices:
"pdb_ssbond_pkey" PRIMARY KEY, btree (id) "ndxcode1" btree (code, chain_id1, res_seq1) "ndxcode2" btree (code, chain_id2, res_seq2)
Supõe-se que a distribuição de ligações dissulfeto antes do corte é gaussiana (sem testar com, por exemplo, teste KS), então os desvios padrão foram calculados em cada distância entre cisteínas na mesma proteína para descobrir a faixa de comprimentos de ligação permitidos e compará-los ao corte. O ponto de corte foi o mesmo que a média calculada mais-menos três desvios padrão. Estendemos o alcance para introduzir mais ligações dissulfeto possíveis que não foram listadas no arquivo PDB em linhas SSBOND
, mas que inserimos calculando distâncias entre registros ATOM
. O intervalo escolhido para ssbonds
está entre 1,6175344456264 e 2,48801947642267 Å, que é a média (2,05) mais-menos quatro desvios padrão:
select count(1) as cnt , stddev(dist) as std_dev , avg(dist) as avg_val , -stddev(dist) + avg(dist) as left1 , stddev(dist) + avg(dist) as right1 , -2 * stddev(dist) + avg(dist) as left2 , 2 * stddev(dist) + avg(dist) as right2 , -3 * stddev(dist) + avg(dist) as left3 , 3 * stddev(dist) + avg(dist) as right3 , -4 * stddev(dist) + avg(dist) as left4 , 4 * stddev(dist) + avg(dist) as right4 , min(dist) , max(dist) from pdb_ssbond_tmp where dist > 0 and dist < 20;
A tabela TS
contém as coordenadas de todos os átomos, mas apenas as cisteínas serão usadas, com seu enxofre denominado " SG "
. Assim, outra tabela de teste com apenas átomos de enxofre " SG "
é criada para acelerar o processo reduzindo o número de registros a serem pesquisados. Ao selecionar apenas enxofres, o número de combinações é muito menor do que no caso de todos os átomos – 194.574 do primeiro em comparação com 122.761.100 do último. Dentro desta tabela unida a si mesma, as distâncias são calculadas usando a distância euclidiana, e os resultados são importados para a tabela pdb_ssbond
, mas somente onde a distância está entre os comprimentos definidos calculados anteriormente. A razão para fazer essa aceleração é diminuir o tempo de execução de todo o processo novamente - para fins de verificação - mantendo-o em um dia.
Para limpar ligações dissulfeto, usamos o seguinte algoritmo:
- Excluir quando ambos os lados da conexão apontam para o mesmo aminoácido
- Excluir títulos cujo comprimento não esteja entre 1,6175344456264 e 2,48801947642267
- Remover inserções
- Remova as ligações causadas por locais alternativos dos átomos, mas deixando o primeiro local
O código para isso (tomando a tabela pdb_ssbond
como o primeiro argumento) é:
CREATE OR REPLACE FUNCTION pdb_ssbond_clean2( clean_icodes boolean, clean_altloc boolean, mark_reactive boolean, mark_consecutive boolean) RETURNS void AS $$ declare _res integer; BEGIN delete from pdb_ssbond b where exists ( select a.id from pdb_ssbond a where a.code = b.code and a.id > b.id and ( ( a.chain_id1 = b.chain_id1 and a.res_seq1 = b.res_seq1 and a.chain_id2 = b.chain_id2 and a.res_seq2 = b.res_seq2) or ( a.chain_id1 = b.chain_id2 and a.res_seq1 = b.res_seq2 and a.chain_id2 = b.chain_id1 and a.res_seq2 = b.res_seq1) ) ) ; delete from pdb_ssbond where chain_id1 = chain_id2 and res_seq1 = res_seq2 and i_code1 = i_code2; update pdb_ssbond set is_consecutive = true , is_reactive = false; delete from pdb_ssbond where not dist between 1.6175344456264 and 2.48801947642267; if clean_icodes then delete from pdb_ssbond where i_code1 not in ('', ' ', 'A') or i_code2 not in ('', ' ', 'A') ; end if; if clean_altloc then delete from pdb_ssbond a where exists ( select 1 from pdb_ssbond b where b.code = a.code and b.chain_id1 = a.chain_id1 and b.res_seq1 = a.res_seq1 and b.i_code1 = a.i_code1 and b.ser_num < a.ser_num ) ; delete from pdb_ssbond a where exists ( select 1 from pdb_ssbond b where b.code = a.code and b.chain_id2 = a.chain_id2 and b.res_seq2 = a.res_seq2 and b.i_code2 = a.i_code2 and b.ser_num < a.ser_num ) ; end if; if mark_reactive then update pdb_ssbond set is_reactive = false ; update pdb_ssbond set is_reactive = true where exists ( select 1 from pdb_ssbond b where b.code = pdb_ssbond.code and b.chain_id1 = pdb_ssbond.chain_id1 and b.res_seq1 = pdb_ssbond.res_seq1 and b.i_code1 = pdb_ssbond.i_code1 and b.ser_num < pdb_ssbond.ser_num ) ; update pdb_ssbond set is_reactive = true where exists ( select 1 from pdb_ssbond b where b.code = pdb_ssbond.code and b.chain_id2 = pdb_ssbond.chain_id2 and b.res_seq2 = pdb_ssbond.res_seq2 and b.i_code2 = pdb_ssbond.i_code2 and b.ser_num < pdb_ssbond.ser_num ) ; update pdb_ssbond set is_reactive = true where (code, chain_id1, res_seq1, i_code1) in ( select code, chain_id1 as c, res_seq1 as r, i_code1 as i from pdb_ssbond intersect select code, chain_id2 as c, res_seq2 as r, i_code2 as i from pdb_ssbond ) ; update pdb_ssbond set is_reactive = true where (code, chain_id2, res_seq2, i_code2) in ( select code, chain_id1 as c, res_seq1 as r, i_code1 as i from pdb_ssbond intersect select code, chain_id2 as c, res_seq2 as r, i_code2 as i from pdb_ssbond ); end if; if mark_consecutive then update pdb_ssbond set is_consecutive = false; update pdb_ssbond set is_consecutive = true where not exists ( select 1 from pdb_ssbond a where a.code = pdb_ssbond.code and ( (a.chain_id1 = pdb_ssbond.chain_id1 and a.chain_id2 = pdb_ssbond.chain_id2) or (a.chain_id1 = pdb_ssbond.chain_id2 and a.chain_id2 = pdb_ssbond.chain_id1) ) and ( (a.res_seq1 between pdb_ssbond.res_seq1 and pdb_ssbond.res_seq2) or (a.res_seq2 between pdb_ssbond.res_seq1 and pdb_ssbond.res_seq2) or (pdb_ssbond.res_seq1 between a.res_seq1 and a.res_seq2) or (pdb_ssbond.res_seq2 between a.res_seq1 and a.res_seq2) ) and not ( a.code = pdb_ssbond.code and a.chain_id1 = pdb_ssbond.chain_id1 and a.chain_id2 = pdb_ssbond.chain_id2 and a.res_seq1 = pdb_ssbond.res_seq1 and a.res_seq2 = pdb_ssbond.res_seq2 ) ); end if; END; $$ LANGUAGE plpgsql;
Com isso, o conjunto não redundante de proteínas é importado para a tabela nr
que se junta às tabelas ps
e proteins
, e os conjuntos são marcados ( set7
, set40
e set80
). Ao final, de acordo com a quantidade de proteína, apenas um conjunto será analisado. As cadeias incompatíveis entre PDB e NR são removidas da análise.
Proteínas sem ligações dissulfeto são excluídas da pesquisa, juntamente com proteínas que não pertencem a nenhum conjunto. Os dados são processados com DSSP, e esses arquivos que tiveram problemas de resolução ou muitos átomos para serem processados também são excluídos. Apenas proteínas com cadeias simples são usadas como resultado para análise porque as conexões intercadeias não foram mantidas, embora sejam facilmente calculadas a partir da tabela ssbond
contando o número de conexões que possuem cadeias diferentes.
Para as proteínas restantes, é feita uma atualização do número total de ligações e do número de ligações sobrepostas, e isso é feito para cada um dos conjuntos.
O organismo de origem é extraído dos registros SOURCE
. Nos casos em que é desconhecido, sintético, projetado, artificial ou híbrido, é descartado da pesquisa. As proteínas de baixa resolução também são excluídas apenas quando sua cadeia lateral não é visível.
Os registros SOURCE
são armazenados na tabela de sources
, que contém linhas de taxonomia. Em alguns casos, a taxonomia está ausente ou incorreta. Nesses casos, é necessária a correção manual de especialistas.
A partir da fonte e taxonomia baixadas do NCBI, a classe é atribuída a cada estrutura primária. Caso uma classe não possa ser atribuída, a proteína é removida da lista de análise. Sabendo que os bancos de dados biológicos estão sendo usados, uma verificação extra de todos os registros de origem e classes de taxonomia do NCBI é recomendada a ser realizada por um biólogo, caso contrário, pode haver problemas com classificações entre os diferentes domínios. Para corresponder locais de celular de origem com IDs de taxonomia, os dados da tabela de origem são extraídos para a tabela sources_organela
, onde todos os dados são gravados como código, tag e valor. Seu formato é mostrado abaixo:
select * from sources_organela where code = '1rav';
código | mol_id | marcação | valor |
---|---|---|---|
1rav | 0 | MOL_ID | 1 |
1rav | 7 | CELULAR_LOCATION | CITOPLASMA (BRANCO) |
O arquivo de taxonomia que queremos usar é um arquivo ZIP contendo sete arquivos de despejo. Entre esses arquivos, dois dos mais importantes são names.dmp
e merged.dmp
. Ambos os arquivos são arquivos delimitados por tab-pipe CSV, conforme detalhado na documentação:
- O arquivo
merged.dmp
contém uma lista de IDs de taxonomia anteriores e os IDs de taxonomia atuais nos quais cada um foi mesclado. -
names.dmp
contém estas colunas importantes nesta ordem:-
tax_id
: o ID da taxonomia -
name_txt
: O nome da espécie e, se aplicável, o nome exclusivo (onde as espécies podem ser encontradas com vários nomes, isso ajuda a desambiguar)
-
-
division.dmp
contém os nomes dos domínios de nível superior que usaremos como nossas classes. -
nodes.dmp
é a tabela que contém uma estrutura hierárquica de organismos usando IDs de taxonomia.- Ele contém um ID de taxonomia pai, uma chave estrangeira que pode ser encontrada em
names.dmp
. - Ele também contém um ID de divisão que é importante para armazenarmos corretamente os dados relevantes do domínio principal.
- Ele contém um ID de taxonomia pai, uma chave estrangeira que pode ser encontrada em
Com todos esses dados e correções manuais (definindo domínios de vida corretos) conseguimos criar a estrutura da tabela taxonomy_path
. Uma amostra de dados se parece com isso:
select * from taxonomy_path order by length(path) limit 20 offset 2000;
CPF | caminho | is_viral | é_eucarioto | is_archaea | é_outro | is_procariote |
---|---|---|---|---|---|---|
142182 | organismos celulares;Bactérias;Gemmatimonadetes | f | f | f | f | t |
136087 | organismos celulares; Eucariotos; Malawimonadidae | f | t | f | f | f |
649454 | Vírus; fagos não classificados; Cyanophage G1168 | t | f | f | f | f |
321302 | Vírus; vírus não classificados; vírus Tellina 1 | t | f | f | f | f |
649453 | Vírus; fagos não classificados; Cyanophage G1158 | t | f | f | f | f |
536461 | Vírus; fagos não classificados; Cyanophage S-SM1 | t | f | f | f | f |
536462 | Vírus; fagos não classificados; Cyanophage S-SM2 | t | f | f | f | f |
77041 | Vírus; vírus não classificados; vírus furtivo 4 | t | f | f | f | f |
77042 | Vírus; vírus não classificados; vírus furtivo 5 | t | f | f | f | f |
641835 | Vírus; fagos não classificados; fago Vibrio 512 | t | f | f | f | f |
1074427 | Vírus; vírus não classificados; Mouse Rosavirus | t | f | f | f | f |
1074428 | Vírus; vírus não classificados;Mouse Mosavirus | t | f | f | f | f |
480920 | outras sequências;plasmídeos;IncP-1 plasmídeo 6-S1 | f | f | f | t | f |
2441 | other sequences;plasmids;Plasmid ColBM-Cl139 | f | f | f | t | f |
168317 | other sequences;plasmids;IncQ plasmid pIE723 | f | f | f | t | f |
536472 | Viruses;unclassified phages;Cyanophage Syn10 | t | f | f | f | f |
536474 | Viruses;unclassified phages;Cyanophage Syn30 | t | f | f | f | f |
2407 | other sequences;transposons;Transposon Tn501 | f | f | f | t | f |
227307 | Viruses;ssDNA viruses;Circoviridae;Gyrovirus | t | f | f | f | f |
687247 | Viruses;unclassified phages;Cyanophage ZQS-7 | t | f | f | f | f |
Before any analysis, to avoid biases, sequences have to be checked for their level of identity. Although the NR set contains sequences which are already compared between each other, an extra check is always recommended.
For each disulfide bond's prior statistical analysis, data is marked if it is reactive or overlapping. After marking overlaps, that information automatically reveals how many consecutive and non-consecutive bonds are inside each protein, and that data is stored in the proteins
table from which all protein complexes are excluded in final result.
Each disulfide bond is marked also for its association to sets, by checking both bond sides to see if they belong to the same NR set. Where that is not the case, the disulfide bond is skipped for that set analysis.
To analyze the quantity of bonds by their variance, each length has to be put in a specific class. In this case, only five classes are chosen as written in the function below.
CREATE OR REPLACE FUNCTION len2class(len integer) RETURNS integer AS $BODY$ BEGIN return case when len <= 100 then 1 when len > 100 and len <= 200 then 2 when len > 200 and len <= 300 then 3 when len > 300 and len <= 400 then 4 else 5 end; END; $BODY$ LANGUAGE plpgsql VOLATILE COST 100;
Most of the protein sizes are less than 400 amino acids, so length classification is done by splitting lengths into five ranges, each taking 100 amino acids, except the last one which takes the rest. Below you can see how to use this function to extract data for analysis:
SELECT p.code, p.title, p.ss_bonds, p.ssbonds_overlap, p.intra_count, p.sci_name_src, p.len, p.tax_path, p.pfam_families, p.src_class, ( SELECT s.id FROM src_classes s WHERE s.src_class::text = p.src_class::text) AS src_class_id, p.len_class7, ( SELECT s.val FROM sources_organela s WHERE s.code = p.code::bpchar AND s.tag::text = 'EXPRESSION_SYSTEM_CELLULAR_LOCATION'::text) AS expression_system_cellular_location, ( SELECT s.val FROM sources_organela s WHERE s.code = p.code::bpchar AND s.tag::text = 'CELLULAR_LOCATION'::text) AS cellular_location, ps.sequence, ps.uniprot_code, ps.accession_code, ps.cc, ps.seq_uniprot, ps.chain_id FROM proteins p JOIN nr n ON n.code::text = p.code::text AND n.rep7 = true JOIN ps ps ON ps.code::text = n.code::text AND ps.chain_id = n.chain_id AND ps.het = false WHERE p.is_excluded = false AND p.chain_cnt = 1 AND p.is_set7 = true AND p.reactive_cnt7 = 0 ORDER BY p.code;
An example result with corrected titles and some manually added columns is shown below.
Código PDB | Número total de títulos SS | Número de títulos SS não consecutivos | Comprimento PDB / aminoácidos | Domínio | Alvo P 1.1 | TatP 1.0 | Sinal P 4.1 | CloroP 1.1 | TMHMM 2.0 número de domínios transmembranares | Big-pi | nucPred | NetNES 1.1 | PSORTb v3.0 | Secretoma P 2.0 | LocTree2 | Previsão de localização de consenso |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1kp | 2 | 0 | 114 | Bactérias | ND | Tat-sinal | nenhum peptídeo sinal | ND | 0 | ND | ND | ND | desconhecido | ND | fímbrio | desconhecido |
1 bhu | 2 | 0 | 102 | Bactérias | ND | Tat-sinal | peptídeo de sinal | ND | 1 | ND | ND | ND | desconhecido | ND | secretado | desconhecido |
1c75 | 0 | 0 | 71 | Bactérias | ND | Tat-sinal | nenhum peptídeo sinal | ND | 0 | ND | ND | ND | Membrana citoplasmática | secreção não clássica | periplasma | desconhecido |
1c8x | 0 | 0 | 265 | Bactérias | ND | Tat-sinal | peptídeo de sinal | ND | 1 | ND | ND | ND | desconhecido | ND | secretado | desconhecido |
1cx1 | 1 | 0 | 153 | Bactérias | ND | Tat-sinal | peptídeo de sinal | ND | 1 | ND | ND | ND | extracelular | ND | secretado | desconhecido |
1 dab | 0 | 0 | 539 | Bactérias | ND | Tat-sinal | peptídeo de sinal | ND | 0 | ND | ND | ND | membrana externa | ND | membrana externa | desconhecido |
1dfu | 0 | 0 | 94 | Bactérias | ND | Tat-sinal | nenhum peptídeo sinal | ND | 0 | ND | ND | ND | citoplasmático | ND | citosol | desconhecido |
1e8r | 2 | 2 | 50 | Bactérias | ND | Tat-sinal | peptídeo de sinal | ND | 0 | ND | ND | ND | desconhecido | ND | secretado | secretado |
1esc | 3 | 0 | 302 | Bactérias | ND | Tat-sinal | peptídeo de sinal | ND | 1 | ND | ND | ND | extracelular | ND | periplasma | desconhecido |
1g6e | 1 | 0 | 87 | Bactérias | ND | Tat-sinal | peptídeo de sinal | ND | 1 | ND | ND | ND | desconhecido | ND | secretado | desconhecido |
PostgreSQL como intermediário de processamento
Neste trabalho, mostramos como processar dados, desde a busca até a análise. Ao trabalhar com dados científicos, às vezes a normalização é necessária, às vezes não. Ao trabalhar com pequenas quantidades de dados que não serão reutilizados para outra análise, basta deixá-los desnormalizados onde o processamento é rápido o suficiente.
A razão pela qual tudo isso foi feito em um banco de dados de bioinformática é que o PostgreSQL é capaz de integrar muitas linguagens. Isso inclui o R, que pode fazer análises estatísticas diretamente no banco de dados – assunto para um artigo futuro sobre ferramentas de bioinformática.
Um agradecimento especial aos colegas da Toptal Stefan Fuchs e Aldo Zelen por suas inestimáveis consultas.