From 34b6757216f83a7ae073c6792a25d1fd6a5309f4 Mon Sep 17 00:00:00 2001 From: Anton Petrov Date: Wed, 4 Dec 2024 22:56:25 +0000 Subject: [PATCH 01/15] Embed XRNA-GT video and link to playlist in docs --- docs/editors.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/editors.md b/docs/editors.md index 4d077cfc1..4d05318dc 100644 --- a/docs/editors.md +++ b/docs/editors.md @@ -64,6 +64,16 @@ Watch RNAcanvas editing R2DT output in action: Edit an example structure in xRNA React +Get started with XRNA-React by watching the introductory video below, and explore additional tutorials in the following [YouTube playlist](https://www.youtube.com/playlist?list=PLoWAPeA39A2hPTBUEXWLB7_6-R6vGhLT_). + +```{eval-rst} +.. raw:: html + +
+ +
+``` + ### Constraint modes Within a given mode, all nucleotides in a group are automatically selected, upon left-clicking a mouse over a particular nucleotide within the desired region of the RNA scene. Nucleotide positions can further be transformed (edited) according to certain rules specific to a given mode. For example, the position of a single nucleotide can be adjusted in x and y directions; positions of nucleotides in a selected single-stranded region can be adjusted to an equally spaced straight line, or an arch of a given radius; positions of a single base pair can be adjusted in x or y directions, as well as their rotational orientation can also be specified. All selected objects are transformed as rigid bodies, respecing the existing base pairing topology. From a363a77f8aa3dd689c03cfce8d9243bccc20bb68 Mon Sep 17 00:00:00 2001 From: Anton Petrov Date: Tue, 17 Dec 2024 14:28:17 +0000 Subject: [PATCH 02/15] Add XRNA-React user manual --- docs/editors.md | 12 +- docs/files/5S_E_coli.json | 1 + docs/files/5S_E_coli.xrna | 127 ++++++++++ docs/xrna-react-user-guide.md | 425 ++++++++++++++++++++++++++++++++++ 4 files changed, 556 insertions(+), 9 deletions(-) create mode 100644 docs/files/5S_E_coli.json create mode 100644 docs/files/5S_E_coli.xrna create mode 100644 docs/xrna-react-user-guide.md diff --git a/docs/editors.md b/docs/editors.md index 4d05318dc..a7146cb8d 100644 --- a/docs/editors.md +++ b/docs/editors.md @@ -64,15 +64,9 @@ Watch RNAcanvas editing R2DT output in action: Edit an example structure in xRNA React -Get started with XRNA-React by watching the introductory video below, and explore additional tutorials in the following [YouTube playlist](https://www.youtube.com/playlist?list=PLoWAPeA39A2hPTBUEXWLB7_6-R6vGhLT_). - -```{eval-rst} -.. raw:: html - -
- -
-``` +:::{note} +Explore [User Manual](xrna-react-user-guide.md) to watch video tutorials and see it in action. +::: ### Constraint modes diff --git a/docs/files/5S_E_coli.json b/docs/files/5S_E_coli.json new file mode 100644 index 000000000..de1eabff9 --- /dev/null +++ b/docs/files/5S_E_coli.json @@ -0,0 +1 @@ +{"classes":[{"name":"font#0","font-family":"Helvetica","font-size":"8.334300px","font-weight":"bold","font-style":"normal"},{"name":"stroke#0","stroke-width":"0.5209","stroke":"rgb(204, 204, 204)"}],"rnaComplexes":[{"name":"complex","rnaMolecules":[{"name":"molecule","basePairs":[{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":1,"residueIndex2":119},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":2,"residueIndex2":118},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":3,"residueIndex2":117},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":4,"residueIndex2":116},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":5,"residueIndex2":115},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":6,"residueIndex2":114},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":7,"residueIndex2":113},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":8,"residueIndex2":112},{"basePairType":"wobble","classes":["stroke#1"],"residueIndex1":9,"residueIndex2":111},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":10,"residueIndex2":110},{"basePairType":"wobble","classes":["stroke#1"],"residueIndex1":18,"residueIndex2":65},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":19,"residueIndex2":64},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":20,"residueIndex2":63},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":21,"residueIndex2":62},{"basePairType":"wobble","classes":["stroke#1"],"residueIndex1":22,"residueIndex2":61},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":23,"residueIndex2":60},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":28,"residueIndex2":56},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":29,"residueIndex2":55},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":30,"residueIndex2":54},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":31,"residueIndex2":51},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":32,"residueIndex2":50},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":33,"residueIndex2":49},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":34,"residueIndex2":48},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":70,"residueIndex2":106},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":71,"residueIndex2":105},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":73,"residueIndex2":103},{"basePairType":"wobble","classes":["stroke#1"],"residueIndex1":74,"residueIndex2":102},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":79,"residueIndex2":97},{"basePairType":"wobble","classes":["stroke#1"],"residueIndex1":80,"residueIndex2":96},{"basePairType":"wobble","classes":["stroke#1"],"residueIndex1":81,"residueIndex2":95},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":82,"residueIndex2":94},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":83,"residueIndex2":93},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":84,"residueIndex2":92},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":85,"residueIndex2":91},{"basePairType":"canonical","classes":["stroke#1"],"residueIndex1":86,"residueIndex2":90}],"labels":[{"residueIndex":10,"labelContent":{"classes":["text-rgb(0, 0, 0)","font#0"],"label":"10","x":57.37842798616583,"y":78.32288330560166},"labelLine":{"classes":["stroke#0"],"points":[{"x":45.581737979568146,"y":85.39002478420858},{"x":52.37784796144663,"y":81.31862249091742}]}},{"residueIndex":20,"labelContent":{"classes":["text-rgb(0, 0, 0)","font#0"],"label":"20","x":90.51523764374625,"y":102.04711651867359},"labelLine":{"classes":["stroke#0"],"points":[{"x":90.51523764374625,"y":115.79871220028113},{"x":90.51523764374625,"y":106.21426653927293}]}},{"residueIndex":30,"labelContent":{"classes":["text-rgb(0, 0, 0)","font#0"],"label":"30","x":155.51523764374625,"y":102.04711651867359},"labelLine":{"classes":["stroke#0"],"points":[{"x":155.51523764374625,"y":115.79871220028113},{"x":155.5152376437462,"y":106.21426653927293}]}},{"residueIndex":50,"labelContent":{"classes":["text-rgb(0, 0, 0)","font#0"],"label":"50","x":172.50761882187314,"y":160.08553338830248},"labelLine":{"classes":["stroke#0"],"points":[{"x":172.50761882187314,"y":146.3339377066949},{"x":172.5076188218732,"y":155.91838336770311}]}},{"residueIndex":100,"labelContent":{"classes":["text-rgb(0, 0, 0)","font#0"],"label":"100","x":3.510684727538546,"y":187.3520325182712},"labelLine":{"classes":["stroke#0"],"points":[{"x":16.343516010498888,"y":192.29418033612143},{"x":11.011554478515109,"y":190.2407486756316}]}}],"sequence":[{"classes":["text-rgb(0, 128, 0)","font#0"],"residueIndex":0,"residueName":"5'","x":41,"y":7.89129650552627},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":1,"residueName":"U","x":41.292032626861555,"y":15.891324953488038},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":2,"residueName":"G","x":41.292032626861555,"y":23.89894377536116},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":3,"residueName":"C","x":41.292032626861555,"y":31.906562597234288},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":4,"residueName":"C","x":41.292032626861555,"y":39.914181419107415},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":5,"residueName":"U","x":41.292032626861555,"y":47.92180024098054},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":6,"residueName":"G","x":41.292032626861555,"y":55.92941906285366},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":7,"residueName":"G","x":41.292032626861555,"y":63.93703788472679},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":8,"residueName":"C","x":41.292032626861555,"y":71.94465670659991},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":9,"residueName":"G","x":42.83583752089079,"y":79.95227552847304},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":10,"residueName":"G","x":41.292032626861555,"y":87.95989435034616},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":11,"residueName":"C","x":46.53032751568689,"y":91.70286722736378},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":12,"residueName":"C","x":52.889999999999986,"y":95.12132495348803},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":13,"residueName":"G","x":56.920000000000016,"y":100.79132495348804},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":14,"residueName":"U","x":59.27999999999997,"y":107.33132495348804},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":15,"residueName":"A","x":59.81,"y":114.26132495348804},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":16,"residueName":"G","x":58.5,"y":120.79929232662647},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":17,"residueName":"C","x":66.50761882187312,"y":120.79929232662647},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":18,"residueName":"G","x":74.5,"y":119.25548743259723},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":19,"residueName":"C","x":82.50761882187312,"y":120.79929232662647},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":20,"residueName":"G","x":90.51523764374625,"y":120.79929232662647},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":21,"residueName":"G","x":98.52285646561938,"y":120.79929232662647},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":22,"residueName":"U","x":106.5304752874925,"y":119.25548743259723},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":23,"residueName":"G","x":114.53809410936563,"y":120.79929232662647},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":24,"residueName":"G","x":116.10000000000002,"y":112.69132495348805},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":25,"residueName":"U","x":122.69999999999999,"y":107.19132495348805},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":26,"residueName":"C","x":131.3,"y":107.19132495348805},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":27,"residueName":"C","x":137.89999999999998,"y":112.59132495348803},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":28,"residueName":"C","x":139.5,"y":120.79929232662647},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":29,"residueName":"A","x":147.50761882187314,"y":120.79929232662647},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":30,"residueName":"C","x":155.51523764374625,"y":120.79929232662647},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":31,"residueName":"C","x":164.5,"y":120.74929232662649},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":32,"residueName":"U","x":172.50761882187314,"y":120.74929232662649},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":33,"residueName":"G","x":180.51523764374625,"y":120.74929232662649},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":34,"residueName":"A","x":188.52285646561938,"y":120.74929232662649},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":35,"residueName":"C","x":193.7,"y":114.39132495348804},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":36,"residueName":"C","x":201,"y":110.09132495348803},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":37,"residueName":"C","x":209.5,"y":108.79132495348804},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":38,"residueName":"C","x":217.8,"y":110.79132495348804},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":39,"residueName":"A","x":224.7,"y":115.59132495348803},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":40,"residueName":"U","x":229.3,"y":122.89132495348804},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":41,"residueName":"G","x":230.89999999999998,"y":131.19132495348805},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":42,"residueName":"C","x":229.3,"y":139.59132495348803},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":43,"residueName":"C","x":224.60000000000002,"y":146.59132495348803},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":44,"residueName":"G","x":217.7,"y":151.59132495348803},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":45,"residueName":"A","x":209.39999999999998,"y":153.49132495348806},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":46,"residueName":"A","x":201,"y":152.19132495348805},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":47,"residueName":"C","x":193.60000000000002,"y":147.79132495348802},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":48,"residueName":"U","x":188.52285646561938,"y":141.3333575803496},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":49,"residueName":"C","x":180.51523764374625,"y":141.3333575803496},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":50,"residueName":"A","x":172.50761882187314,"y":141.3333575803496},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":51,"residueName":"G","x":164.5,"y":141.3333575803496},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":52,"residueName":"A","x":164,"y":149.09132495348803},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":53,"residueName":"A","x":156,"y":149.09132495348803},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":54,"residueName":"G","x":155.51523764374625,"y":141.38335758034958},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":55,"residueName":"U","x":147.50761882187314,"y":141.38335758034958},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":56,"residueName":"G","x":139.5,"y":141.38335758034958},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":57,"residueName":"A","x":135,"y":147.78132495348802},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":58,"residueName":"A","x":127.07,"y":150.31132495348805},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":59,"residueName":"A","x":119.13,"y":147.84132495348803},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":60,"residueName":"C","x":114.53809410936563,"y":141.38335758034958},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":61,"residueName":"G","x":106.5304752874925,"y":142.9271624743788},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":62,"residueName":"C","x":98.52285646561938,"y":141.38335758034958},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":63,"residueName":"C","x":90.51523764374625,"y":141.38335758034958},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":64,"residueName":"G","x":82.50761882187312,"y":141.38335758034958},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":65,"residueName":"U","x":74.5,"y":142.9271624743788},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":66,"residueName":"A","x":70.5,"y":148.09132495348803},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":67,"residueName":"G","x":66.50761882187312,"y":141.38335758034958},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":68,"residueName":"C","x":58.5,"y":141.38335758034958},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":69,"residueName":"G","x":49.72999999999999,"y":142.00132495348805},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":70,"residueName":"C","x":41.292032626861555,"y":146.09132495348803},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":71,"residueName":"C","x":41.292032626861555,"y":154.09894377536116},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":72,"residueName":"G","x":40.99000000000001,"y":162.09132495348803},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":73,"residueName":"A","x":41.292032626861555,"y":170.09132495348803},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":74,"residueName":"U","x":42.83583752089079,"y":178.09894377536116},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":75,"residueName":"G","x":40.99000000000001,"y":186.09132495348803},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":76,"residueName":"G","x":40.99000000000001,"y":194.09132495348803},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":77,"residueName":"U","x":48.06,"y":201.16132495348802},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":78,"residueName":"A","x":48.02000000000001,"y":211.11132495348807},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":79,"residueName":"G","x":41.25203262686155,"y":218.09132495348803},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":80,"residueName":"U","x":42.795837520890785,"y":226.09894377536116},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":81,"residueName":"G","x":42.795837520890785,"y":234.10656259723427},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":82,"residueName":"U","x":41.25203262686155,"y":242.1141814191074},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":83,"residueName":"G","x":41.25203262686155,"y":250.12180024098052},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":84,"residueName":"G","x":41.25203262686155,"y":258.12941906285363},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":85,"residueName":"G","x":41.25203262686155,"y":266.1370378847268},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":86,"residueName":"G","x":41.25203262686155,"y":274.1446567065999},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":87,"residueName":"U","x":38.879999999999995,"y":282.56132495348805},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":88,"residueName":"C","x":30.909999999999997,"y":286.30132495348806},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":89,"residueName":"U","x":23.080000000000013,"y":282.61132495348807},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":90,"residueName":"C","x":20.66796737313844,"y":274.1446567065999},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":91,"residueName":"C","x":20.66796737313844,"y":266.1370378847268},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":92,"residueName":"C","x":20.66796737313844,"y":258.12941906285363},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":93,"residueName":"C","x":20.66796737313844,"y":250.12180024098052},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":94,"residueName":"A","x":20.66796737313844,"y":242.1141814191074},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":95,"residueName":"U","x":19.124162479109202,"y":234.10656259723427},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":96,"residueName":"G","x":19.124162479109202,"y":226.09894377536116},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":97,"residueName":"C","x":20.66796737313844,"y":218.09132495348803},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":98,"residueName":"G","x":15.099999999999994,"y":210.71132495348803},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":99,"residueName":"A","x":15.110000000000014,"y":201.41132495348802},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":100,"residueName":"G","x":21.00999999999999,"y":194.09132495348803},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":101,"residueName":"A","x":21.00999999999999,"y":186.09132495348803},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":102,"residueName":"G","x":19.16416247910921,"y":178.09894377536116},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":103,"residueName":"U","x":20.707967373138445,"y":170.09132495348803},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":104,"residueName":"A","x":21.00999999999999,"y":162.09132495348803},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":105,"residueName":"G","x":20.707967373138445,"y":154.09894377536116},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":106,"residueName":"G","x":20.707967373138445,"y":146.09132495348803},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":107,"residueName":"G","x":5.72999999999999,"y":134.84132495348803},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":108,"residueName":"A","x":0,"y":116.91132495348805},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":109,"residueName":"A","x":7.962739607483979,"y":100.01489455156376},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":110,"residueName":"C","x":20.707967373138445,"y":87.95989435034616},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":111,"residueName":"U","x":19.16416247910921,"y":79.95227552847304},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":112,"residueName":"G","x":20.707967373138445,"y":71.94465670659991},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":113,"residueName":"C","x":20.707967373138445,"y":63.93703788472679},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":114,"residueName":"C","x":20.707967373138445,"y":55.92941906285366},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":115,"residueName":"A","x":20.707967373138445,"y":47.92180024098054},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":116,"residueName":"G","x":20.707967373138445,"y":39.914181419107415},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":117,"residueName":"G","x":20.707967373138445,"y":31.906562597234288},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":118,"residueName":"C","x":20.707967373138445,"y":23.89894377536116},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":119,"residueName":"A","x":20.707967373138445,"y":15.891324953488038},{"classes":["text-rgb(0, 0, 0)","font#0"],"residueIndex":120,"residueName":"U","x":21,"y":7.89129650552627},{"classes":["text-rgb(0, 128, 0)","font#0"],"residueIndex":121,"residueName":"3'","x":22.314494058588963,"y":0}]}],"basePairs":[]}]} diff --git a/docs/files/5S_E_coli.xrna b/docs/files/5S_E_coli.xrna new file mode 100644 index 000000000..7d9250b28 --- /dev/null +++ b/docs/files/5S_E_coli.xrna @@ -0,0 +1,127 @@ +5' 0 41.00 -7.89 +U 1 41.29 -15.89 +G 2 41.29 -23.90 +C 3 41.29 -31.91 +C 4 41.29 -39.91 +U 5 41.29 -47.92 +G 6 41.29 -55.93 +G 7 41.29 -63.94 +C 8 41.29 -71.94 +G 9 42.84 -79.95 +G 10 41.29 -87.96 +C 11 46.53 -91.70 +C 12 52.89 -95.12 +G 13 56.92 -100.79 +U 14 59.28 -107.33 +A 15 59.81 -114.26 +G 16 58.50 -120.80 +C 17 66.51 -120.80 +G 18 74.50 -119.26 +C 19 82.51 -120.80 +G 20 90.52 -120.80 +G 21 98.52 -120.80 +U 22 106.53 -119.26 +G 23 114.54 -120.80 +G 24 116.10 -112.69 +U 25 122.70 -107.19 +C 26 131.30 -107.19 +C 27 137.90 -112.59 +C 28 139.50 -120.80 +A 29 147.51 -120.80 +C 30 155.52 -120.80 +C 31 164.50 -120.75 +U 32 172.51 -120.75 +G 33 180.52 -120.75 +A 34 188.52 -120.75 +C 35 193.70 -114.39 +C 36 201.00 -110.09 +C 37 209.50 -108.79 +C 38 217.80 -110.79 +A 39 224.70 -115.59 +U 40 229.30 -122.89 +G 41 230.90 -131.19 +C 42 229.30 -139.59 +C 43 224.60 -146.59 +G 44 217.70 -151.59 +A 45 209.40 -153.49 +A 46 201.00 -152.19 +C 47 193.60 -147.79 +U 48 188.52 -141.33 +C 49 180.52 -141.33 +A 50 172.51 -141.33 +G 51 164.50 -141.33 +A 52 164.00 -149.09 +A 53 156.00 -149.09 +G 54 155.52 -141.38 +U 55 147.51 -141.38 +G 56 139.50 -141.38 +A 57 135.00 -147.78 +A 58 127.07 -150.31 +A 59 119.13 -147.84 +C 60 114.54 -141.38 +G 61 106.53 -142.93 +C 62 98.52 -141.38 +C 63 90.52 -141.38 +G 64 82.51 -141.38 +U 65 74.50 -142.93 +A 66 70.50 -148.09 +G 67 66.51 -141.38 +C 68 58.50 -141.38 +G 69 49.73 -142.00 +C 70 41.29 -146.09 +C 71 41.29 -154.10 +G 72 40.99 -162.09 +A 73 41.29 -170.09 +U 74 42.84 -178.10 +G 75 40.99 -186.09 +G 76 40.99 -194.09 +U 77 48.06 -201.16 +A 78 48.02 -211.11 +G 79 41.25 -218.09 +U 80 42.80 -226.10 +G 81 42.80 -234.11 +U 82 41.25 -242.11 +G 83 41.25 -250.12 +G 84 41.25 -258.13 +G 85 41.25 -266.14 +G 86 41.25 -274.14 +U 87 38.88 -282.56 +C 88 30.91 -286.30 +U 89 23.08 -282.61 +C 90 20.67 -274.14 +C 91 20.67 -266.14 +C 92 20.67 -258.13 +C 93 20.67 -250.12 +A 94 20.67 -242.11 +U 95 19.12 -234.11 +G 96 19.12 -226.10 +C 97 20.67 -218.09 +G 98 15.10 -210.71 +A 99 15.11 -201.41 +G 100 21.01 -194.09 +A 101 21.01 -186.09 +G 102 19.16 -178.10 +U 103 20.71 -170.09 +A 104 21.01 -162.09 +G 105 20.71 -154.10 +G 106 20.71 -146.09 +G 107 5.73 -134.84 +A 108 0.00 -116.91 +A 109 7.96 -100.01 +C 110 20.71 -87.96 +U 111 19.16 -79.95 +G 112 20.71 -71.94 +C 113 20.71 -63.94 +C 114 20.71 -55.93 +A 115 20.71 -47.92 +G 116 20.71 -39.91 +G 117 20.71 -31.91 +C 118 20.71 -23.90 +A 119 20.71 -15.89 +U 120 21.00 -7.89 +3' 121 22.31 0.00l 4.29 2.57 11.09 6.64 0.52 CCCCCC 0.0 0 0 0 0 +s 16.09 9.64 0.0 8.334300px 2 0 "10"l 0.00 5.00 0.00 14.59 0.52 CCCCCC 0.0 0 0 0 0 +s 0.00 18.75 0.0 8.334300px 2 0 "20"l 0.00 5.00 -0.00 14.59 0.52 CCCCCC 0.0 0 0 0 0 +s 0.00 18.75 0.0 8.334300px 2 0 "30"l 0.00 -5.00 0.00 -14.59 0.52 CCCCCC 0.0 0 0 0 0 +s 0.00 -18.75 0.0 8.334300px 2 0 "50"l -4.67 1.80 -10.00 3.85 0.52 CCCCCC 0.0 0 0 0 0 +s -17.50 6.74 0.0 8.334300px 2 0 "100" diff --git a/docs/xrna-react-user-guide.md b/docs/xrna-react-user-guide.md new file mode 100644 index 000000000..4cd52b706 --- /dev/null +++ b/docs/xrna-react-user-guide.md @@ -0,0 +1,425 @@ + +# XRNA-REACT User Guide + +## About XRNA-REACT + +XRNA-REACT is a web-based tool for editing and visualizing RNA secondary structures. It is an upgraded version of the original XRNA software developed by Harry Noller (available as a depreciated [Java applet](http://rna.ucsc.edu/rnacenter/xrna/xrna.html)). Please note that XRNA can be used with a trackpad but works best with a mouse, as several functions require a mouse wheel. + +## Basic Navigation + +1. To begin working with XRNA, you need an input file: + +:::{note} +```{eval-rst} +Download an :download:`example XRNA ` or an :download:`example JSON ` file. +``` +::: + +2. Now that you have an input file, navigate to the "Input/Output" tab to upload it. +3. Once the data is imported, you can continue work in several different ways: + +* Download structure data to a different file type (Input/Output tab) +* Edit structure data (Edit tab) +* Add/remove/edit base pairs (Format tab) +* Add/remove annotations (Annotate tab) +* These options are explained in the “Tabs” and "Constraints" sections of this guide. + +#### Demo + +```{eval-rst} +.. raw:: html + +
+ +
+``` + +## Tabs + +### The Input/Output tab + +Here, you can: + +* Upload input files +* Download output files + +Together, these processes enable conversion between file formats. + +#### How to upload input files + +1. Click the "Open" button (Ctrl + O). +2. Select a file with one of the following supported input-file extensions: + * `.xrna` -the native input-file format of XRNA (an extension of .xml) + * `.xml` -a data-file format native to the internet. Highly similar to .xrna + * `.json` -a general-purpose data-file format native to the internet. Logically equivalent to .xrna + * `.str` -an image-file format containing nucleotide sequences and base pairs + * `.svg` -an image-file format. Can be converted to other image-file formats (e.g. `.jpg`) using external tools +3. Upload the file. + +#### How to download output files + +Within the "Save File" row: + +1. Provide an output-file name. +2. Select one of the following supported output-file extensions: + * `.xrna` -the native input-file format of XRNA (an extension of .xml) + * `.json` -a general-purpose data-file format native to the internet. Logically equivalent to .xrna + * `.csv` -a comma-separated-values file. Logically equivalent to .xrna. Intended for use with RiboVision + * `.bpseq` -a simplified, linear representation of the nucleotide sequence of the scene. + * `.tr` -an XML-like format for R2DT. Contains nucleotides with 2D coordinates. + * `.svg` -an image-file format. Can be converted to other image-file formats (e.g. .jpg) using external tools +3. Click the "Save" button (Ctrl + S) + +#### Demo + +```{eval-rst} +.. raw:: html + +
+ +
+``` + +### The Viewport Tab + +Here, you can manipulate the viewport with precision. +To clarify, the viewport is the main, right-hand component of XRNA. Within it, interactive 2D RNA diagrams are displayed. + +#### Translation + +"Translation" refers to the 2D displacement of the entire viewport. It is synchronized with click-and-drag within the viewport. + +* `x`: The horizontal displacement. Rightward displacement is positive; leftward is negative. +* `y`: The vertical displacement. Upward displacement is positive; downward is negative. + +#### Scale + +"Scale" refers to the "in-and-out zoom" of the entire viewport. It is synchronized with the mousewheel within the viewport. + +* Scrolling up with the mouse wheel increases zoom; this means zooming in. +* Scrolling down does the opposite. + +#### Reset + +In one step, the "Reset" button (`Ctrl + 0`) allows the user to reset all properties of the viewport: + +* translate +* scale + +This places all elements of the scene within view of the user. + +#### Demo + +```{eval-rst} +.. raw:: html + +
+ +
+``` + +### The Edit Tab + +Here, you can edit nucleotide data which has been uploaded and is displayed within the viewport. + +1. Navigate within the viewport to the portion of the scene you plan to edit. +2. Next, do one of the following: + * Select a constraint. Then, left-click on a nucleotide. Drag it to change relevant nucleotide-position data, according to the behavior of the constraint. + * Middle-mouse-click and drag to select one or more nucleotide(s) or label(s). This will populate a menu which will allow you to precisely edit data, according to the behavior of an automatically determined constraint. + * Select a constraint. Then, right-click on a nucleotide. This will populate a menu which will allow you to precisely edit data, according to the behavior of the constraint. + +#### Notes + +* Tutorials on how to use specific constraints are located in the "Constraints" section of this guide. +* Most constraints require you to click on a nucleotide that either is or is not base-paired to another nucleotide. +* Other constraints have more restrictive usage requirements. +* Annotations (i.e. labels) may be edited in the same exact way as nucleotides / nucleotide regions (described above). +* Annotations are not present in some input files, but they can be added within the "Annotate" tab. + +#### Demo + +```{eval-rst} +.. raw:: html + +
+ +
+``` + +### The Format tab + +Here, you can add, delete, or edit base pairs. + +1. Navigate within the viewport to the portion of the scene you plan to format. +2. Do one of the following: + * Middle-mouse-click and drag to select one or more nucleotide(s). This will populate a menu which will allow you to precisely format data, according to the behavior of an automatically determined constraint. + * Select a constraint. Then, right-click on a nucleotide. This will populate a menu which will allow you to format base-pair data, according to the behavior of the constraint + +#### Notes + +* Tutorials on how to use specific constraints are located in the "Constraints" section of this guide. +* Most constraints require you to click on a nucleotide that either is or is not base-paired to another nucleotide. +* Other constraints have more restrictive usage requirements. + +#### Demo + +```{eval-rst} +.. raw:: html + +
+ +
+``` + +### The Annotate Tab + +Here, you can add, delete, or edit annotations (label lines or label content). + +1. Navigate within the viewport to the portion of the scene you plan to annotate. +2. Do one of the following: + * Select a constraint. Then, right-click on a nucleotide. This will populate a menu which will allow you to annotate nucleotides, according to the behavior of the constraint + * Middle-mouse-click and drag to select one or more nucleotide(s). This will populate a menu which will allow you to annotate nucleotides, according to the behavior an automatically determined constraint + +#### Notes + +* Most constraints require you to click on a nucleotide that either is or is not base-paired to another nucleotide. +* Other constraints have more restrictive usage requirements. + +#### Demo + +```{eval-rst} +.. raw:: html + +
+ +
+``` + +### The Setting Tab + +Here, you can change settings which regulate how XRNA.js behaves. +Support for saving your settings is implemented by the pair of upload/download buttons. +Store the "xrna\_settings" file somewhere you will remember for later use. + +#### Demo + +```{eval-rst} +.. raw:: html + +
+ +
+``` + +### Constraints + +#### The “Single Nucleotide” constraint + +This constraint allows the user to interact with a single nucleotide. + +#### Demo + +```{eval-rst} +.. raw:: html + +
+ +
+``` + +#### The “Single Nucleotide” constraint + +This constraint allows the user to interact with a single base pair between two nucleotides. + +#### Demo + +```{eval-rst} +.. raw:: html + +
+ +
+``` + +#### The “RNA single strand” constraint + +This constraint allows the user to interact with a contiguous series of single (non-basepaired) nucleotides. + +#### Demo + +```{eval-rst} +.. raw:: html + +
+ +
+``` + +#### The ”Single Helix” constraint + +This constraint allows the user to interact with a contiguous series of base-paired nucleotides. +"Helix" is defined as two series of nucleotides which are mutually base-paired without gaps. +This involves at most two RNA molecules. + +#### Demo + +```{eval-rst} +.. raw:: html + +
+ +
+``` + +#### The “RNA sub-domain” constraint + +This constraint allows the user to interact with a contiguous series of nucleotides constrainted by a helix. +This constraint involves only one RNA molecule. +This includes all nucleotides with nucleotide indices: + +* Greater than or equal to the least nucleotide index in the helix +* Less than or equal to the greatest nucleotide index in the helix + +#### Demo + +```{eval-rst} +.. raw:: html + +
+ +
+``` + +#### The “RNA stacked helix” constraint + +This constraint allows the user to interact with a contiguous series of helices between RNA molecules. +These helices may be separated by single (non-basepaired) nucleotides, but their mutually-basepaired status must resume outside the single-stranded regions. +This constraint involves at most two RNA molecules. + +#### Demo + +```{eval-rst} +.. raw:: html + +
+ +
+``` + +#### The “RNA cycle” constraint + +This constraint allows the user to interact with a cycle of nucleotides. +An RNA cycle is calculated as follows: + +* Treat the nucleotides as nodes in a graph +* Treat the following as edges in the graph: + + Base pairs between nucleotides + + Neighboring nucleotides within a given RNA molecule (with nucleotide indices i, j such that abs(i - j) = 1) +* Calculate the smallest cycle within the graph involving the clicked-on nucleotide + +#### Demo + +```{eval-rst} +.. raw:: html + +
+ +
+``` + +#### The “RNA molecule” constraint + +This constraint allows the user to interact with a single RNA molecule. + +#### Demo + +```{eval-rst} +.. raw:: html + +
+ +
+``` + +#### The “RNA complex” constraint + +This constraint allows the user to interact with a single RNA complex (which may contain more than one RNA molecule). + +Demo + +```{eval-rst} +.. raw:: html + +
+ +
+``` + +#### The “Single Color” constraint + +This constraint allows the user to interact with all nucleotides or labels with the same color + +#### Demo + +```{eval-rst} +.. raw:: html + +
+ +
+``` + +#### The “Entire Scene” constraint + +This constraint allows the user to interact with all nucleotides or labels within the scene (i.e. viewport) + +#### Demo + +```{eval-rst} +.. raw:: html + +
+ +
+``` + +### Tips and Tricks + +#### Hotkey combinations: + +* `Ctrl + O` - opens a new input file +* `Ctrl + S` - saves a new output file, using the current output-file name and output-file extension. + Fails if either of these are not provided. +* `Ctrl + 0` - resets the properties of the "Viewport" tab. + +#### Demo + +```{eval-rst} +.. raw:: html + +
+ +
+``` + +#### Middle Mouse click + +In order to have a more enjoyable and intuitive experience with XRNA.js, try middle-mouse click-and-drag to highlight nucleotides. +This will: + +1. Automatically change the constraint to an appropriate value which matches the nucleotides you selected +2. Populate a menu for precisely editing, formatting, or annotating data within the viewport. + +#### Demo + +```{eval-rst} +.. raw:: html + +
+ +
+``` + +## Contact Us + +If you have any questions or feedback about XRNA-REACT, please get in touch with Anton S. Petrov at `anton.petrov@biology.gatech.edu`. From f6c4c2a43ff817f973c95df0dce8d2de61acbe63 Mon Sep 17 00:00:00 2001 From: Anton Petrov Date: Tue, 17 Dec 2024 14:28:58 +0000 Subject: [PATCH 03/15] Update examples in R2DT form in docs --- docs/index.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/docs/index.md b/docs/index.md index 745b671ff..3751a1bd8 100644 --- a/docs/index.md +++ b/docs/index.md @@ -12,16 +12,15 @@ The [R2DT software](https://github.com/r2dt-bio/R2DT) automatically generates [R ## Try it now + examples='[ + {"description": "3SKZ_B", "descriptionNote": "Dot-bracket notation", "sequence": "GGCCUUAUACAGGGUAGCAUAAUGGGCUACUGACCCCGCCUUCAAACCUAUUUGGAGACUAUAAGGUC\n.((((((((A..((((((.....BB))))))(.....a)(((((((bb..)))))))..))))))))."}, + {"description": "MT-RNR1", "sequence": "AAUAGGUUUGGUCCUAGCCUUUCUAUUAGCUCUUAGUAAGAUUACACAUGCAAGCAUCCCCGUUCCAGUGAGUUCACCCUCUAAAUCACCACGAUCAAAAGGAACAAGCAUCAAGCACGCAGCAAUGCAGCUCAAAACGCUUAGCCUAGCCACACCCCCACGGGAAACAGCAGUGAUUAACCUUUAGCAAUAAACGAAAGUUUAACUAAGCUAUACUAACCCCAGGGUUGGUCAAUUUCGUGCCAGCCACCGCGGUCACACGAUUAACCCAAGUCAAUAGAAGCCGGCGUAAAGAGUGUUUUAGAUCACCCCCUCCCCAAUAAAGCUAAAACUCACCUGAGUUGUAAAAAACUCCAGUUGACACAAAAUAGACUACGAAAGUGGCUUUAACAUAUCUGAACACACAAUAGCUAAGACCCAAACUGGGAUUAGAUACCCCACUAUGCUUAGCCCUAAACCUCAACAGUUAAAUCAACAAAACUGCUCGCCAGAACACUACGAGCCACAGCUUAAAACUCAAAGGACCUGGCGGUGCUUCAUAUCCCUCUAGAGGAGCCUGUUCUGUAAUCGAUAAACCCCGAUCAACCUCACCACCUCUUGCUCAGCCUAUAUACCGCCAUCUUCAGCAAACCCUGAUGAAGGCUACAAAGUAAGCGCAAGUACCCACGUAAAGACGUUAGGUCAAGGUGUAGCCCAUGAGGUGGCAAGAAAUGGGCUACAUUUUCUACCCCAGAAAACUACGAUAGCCCUUAUGAAACUUAAGGGUCGAAGGUGGAUUUAGCAGUAAACUAAGAGUAGAGUGCUUAGUUGAACAGGGCCCUGAAGCGCGUACACACCGCCCGUCACCCUCCUCAAGUAUACUUCAAAGGACAUUUAACUAAAACCCCUACGCAUUUAUAUAGAGGAGACAAGUCGUAACAUGGUAAGUGUACUGGAAAGUGCACUUGGACGAAC"}, + {"description": "S box leader", "sequence": "ACCTTATTTTGAGAAGCTGAGGGATTTGGCCCATAGAAGCTTCAGCAACCGACTTTAAATAGCACGGTGCTAATACCAACGAGCAACTCGAATGATAAGTA"}, + {"description": "RNVU1-1", "sequence": "AUACUUACCUGGCAGGGGAGAUACGAUGAUCACGAAGGUGGUUUUCCCAGGGAGAGGCUUAUCCAUUGCACUCCGGAUGUGCUGACCCCUGCCGUUUCCCCAAAUGUGGGAAACUCGACUGCAUAAUUUGUGGUAGUGGGGGACUGCGUUCGCGCUGUCCUCUG"}, + {"description": "PDB 3J7Y chain A", "sequence": "GCTAAACCTAGCCCCAAACCCACTCCACCTTACTACCAGACAACCTTAGCCAAACCATTTACCCAAATAAAGTATAGGCGATAGAAATTGAAACCTGGCGCAATAGATATAGTACCGCAAGGGAAAGATGAAAAATTATAACCAAGCATAATATAGCAAGGACTAACCCCTATACCTTCTGCATAATGAATTAACTAGAAATAACTTTGCAAGGAGAGCCAAAGCTAAGACCCCCGAAACCAGACGAGCTACCTAAGAACAGCTAAAAGAGCACACCCGTCTATGTAGCAAAATAGTGGGAAGATTTATAGGTAGAGGCGACAAACCTACCGAGCCTGGTGATAGCTGGTTGTCCAAGATAGAATCTTAGTTCAACTTTAAATTTGCCCACAGAACCCTCTAAATCCCCTTGTAAATTTAACTGTTAGTCCAAAGAGGAACAGCTCTTTGGACACTAGGAAAAAACCTTGTAGAGAGAGTAAAAAATTTAACACCCATAGTAGGCCTAAAAGCAGCCACCAATTAAGAAAGCGTTCAAGCTCAACACCCACTACCTAAAAAATCCCAAACATATAACTGAACTCCTCACACCCAATTGGACCAATCTATCACCCTATAGAAGAACTAATGTTAGTATAAGTAACATGAAAACATTCTCCTCCGCATAAGCCTGCGTCAGATTAAAACACTGAACTGACAATTAACAGCCCAATATCTACAATCAACCAACAAGTCATTATTACCCTCACTGTCAACCCAACACAGGCATGCTCATAAGGAAAGGTTAAAAAAAGTAAAAGGAACTCGGCAAATCTTACCCCGCCTGTTTACCAAAAACATCACCTCTAGCATCACCAGTATTAGAGGCACCGCCTGCCCAGTGACACATGTTTAACGGCCGCGGTACCCTAACCGTGCAAAGGTAGCATAATCACTTGTTCCTTAAATAGGGACCTGTATGAATGGCTCCACGAGGGTTCAGCTGTCTCTTACTTTTAACCAGTGAAATTGACCTGCCCGTGAAGAGGCGGGCATAACACAGCAAGACGAGAAGACCCTATGGAGCTTTAATTTATTAATGCAAACAGTACCTAACAAACCCACAGGTCCTAAACTACCAAACCTGCATTAAAAATTTCGGTTGGGGCGACCTCGGAGCAGAACCCAACCTCCGAGCAGTACATGCTAAGACTTCACCAGTCAAAGCGAACTACTATACTCAATTGATCCAATAACTTGACCAACGGAACAAGTTACCCTAGGGATAACAGCGCAATCCTATTCTAGAGTCCATATCAACAATAGGGTTTACGACCTCGATGTTGGATCAGGACATCCCGATGGTGCAGCCGCTATTAAAGGTTCGTTTGTTCAACGATTAAAGTCCTACGTGATCTGAGTTCAGACCGGAGTAATCCAGGTCGGTTTCTATCTACTTTCAAATTCCTCCCTGTACGAAAGGACAAGAGAAATAAGGCCTACTTCACAAAGCGCCTTCCCCCGTAAATGATATCATCTCAACTTAGTATTATACCCACACCCACCCAAGAACAGGGTTT"}, + {"description": "TRT-TGT2-1", "sequence": "GGCTCCATAGCTCAGTGGTTAGAGCACTGGTCTTGTAAACCAGGGGTCGCGAGTTCGATCCTCGCTGGGGCCT"}, + {"description": "Rn18s", "sequence": "ACCUGGUUGAUCCUGCCAGGUAGCAUAUGCUUGUCUCAAAGAUUAAGCCAUGCAUGUCUAAGUACGCACGGCCGGUACAGUGAAACUGCGAAUGGCUCAUUAAAUCAGUUAUGGUUCCUUUGGUCGCUCGCUCCUCUCCUACUUGGAUAACUGUGGUAAUUCUAGAGCUAAUACAUGCCGACGGGCGCUGACCCCCCUUCCCGGGGGGGGAUGCGUGCAUUUAUCAGAUCAAAACCAACCCGGUGAGCUCCCUCCCGGCUCCGGCCGGGGGUCGGGCGCCGGCGGCUUGGUGACUCUAGAUAACCUCGGGCCGAUCGCACGCCCCCCGUGGCGGCGACGACCCAUUCGAACGUCUGCCCUAUCAACUUUCGAUGGUAGUCGCCGUGCCUACCAUGGUGACCACGGGUGACGGGGAAUCAGGGUUCGAUUCCGGAGAGGGAGCCUGAGAAACGGCUACCACAUCCAAGGAAGGCAGCAGGCGCGCAAAUUACCCACUCCCGACCCGGGGAGGUAGUGACGAAAAAUAACAAUACAGGACUCUUUCGAGGCCCUGUAAUUGGAAUGAGUCCACUUUAAAUCCUUUAACGAGGAUCCAUUGGAGGGCAAGUCUGGUGCCAGCAGCCGCGGUAAUUCCAGCUCCAAUAGCGUAUAUUAAAGUUGCUGCAGUUAAAAAGCUCGUAGUUGGAUCUUGGGAGCGGGCGGGCGGUCCGCCGCGAGGCGAGUCACCGCCCGUCCCCGCCCCUUGCCUCUCGGCGCCCCCUCGAUGCUCUUAGCUGAGUGUCCCGCGGGGCCCGAAGCGUUUACUUUGAAAAAAUUAGAGUGUUCAAAGCAGGCCCGAGCCGCCUGGAUACCGCAGCUAGGAAUAAUGGAAUAGGACCGCGGUUCUAUUUUGUUGGUUUUCGGAACUGAGGCCAUGAUUAAGAGGGACGGCCGGGGGCAUUCGUAUUGCGCCGCUAGAGGUGAAAUUCUUGGACCGGCGCAAGACGGACCAGAGCGAAAGCAUUUGCCAAGAAUGUUUUCAUUAAUCAAGAACGAAAGUCGGAGGUUCGAAGACGAUCAGAUACCGUCGUAGUUCCGACCAUAAACGAUGCCGACUGGCGAUGCGGCGGCGUUAUUCCCAUGACCCGCCGGGCAGCUUCCGGGAAACCAAAGUCUUUGGGUUCCGGGGGGAGUAUGGUUGCAAAGCUGAAACUUAAAGGAAUUGACGGAAGGGCACCACCAGGAGUGGGCCUGCGGCUUAAUUUGACUCAACACGGGAAACCUCACCCGGCCCGGACACGGACAGGAUUGACAGAUUGAUAGCUCUUUCUCGAUUCCGUGGGUGGUGGUGCAUGGCCGUUCUUAGUUGGUGGAGCGAUUUGUCUGGUUAAUUCCGAUAACGAACGAGACUCUGGCAUGCUAACUAGUUACGCGACCCCCGAGCGGUCGGCGUCCCCCAACUUCUUAGAGGGACAAGUGGCGUUCAGCCACCCGAGAUUGAGCAAUAACAGGUCUGUGAUGCCCUUAGAUGUCCGGGGCUGCACGCGCGCUACACUGACUGGCUCAGCGUGUGCCUACCCUGCGCCGGCAGGCGCGGGUAACCCGUUGAACCCCAUUCGUGAUGGGGAUCGGGGAUUGCAAUUAUUCCCCAUGAACGAGGAAUUCCCAGUAAGUGCGGGUCAUAAGCUUGCGUUGAUUAAGUCCCUGCCCUUUGUACACACCGCCCGUCGCUACUACCGAUUGGAUGGUUUAGUGAGGCCCUCGGAUCGGCCCCGCCGGGGUCGGCCCACGGCCCUGGCGGAGCGCUGAGAAGACGGUCGAACUUGACUAUCUAGAGGAAGUAAAAGUCGUAACAAGGUUUCCGUAGGUGAACCUGCGGAAGGAUCAUUAA"} + ]' /> ## How does it work? From 7d3d013c1316d53923be3fdfae0399b88affce38 Mon Sep 17 00:00:00 2001 From: Anton Petrov Date: Tue, 17 Dec 2024 14:35:17 +0000 Subject: [PATCH 04/15] Change admonition type for xrna manual link --- docs/editors.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/editors.md b/docs/editors.md index a7146cb8d..4a1c42065 100644 --- a/docs/editors.md +++ b/docs/editors.md @@ -64,7 +64,7 @@ Watch RNAcanvas editing R2DT output in action: Edit an example structure in xRNA React -:::{note} +:::{tip} Explore [User Manual](xrna-react-user-guide.md) to watch video tutorials and see it in action. ::: From 9216d9ee4ac5c8fb6232c005df2a68972b1d8813 Mon Sep 17 00:00:00 2001 From: Anton Petrov Date: Mon, 10 Feb 2025 16:21:43 +0000 Subject: [PATCH 05/15] Update Readme.md --- Readme.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Readme.md b/Readme.md index b65831d5f..36d5386b6 100644 --- a/Readme.md +++ b/Readme.md @@ -2,9 +2,9 @@ **Version 2.1 (2025)** -**[See the R2DT documentation](https://r2dt.readthedocs.io/)** or read the [latest preprint](https://www.biorxiv.org/content/10.1101/2024.09.29.611006v1). +🚀 **[Read the R2DT documentation](https://r2dt.readthedocs.io/)** | 📄 [Latest paper](https://academic.oup.com/nar/article/53/4/gkaf032/8005627). -The [R2DT software](https://github.com/r2dt-bio/R2DT) automatically generates [RNA secondary structure](https://en.wikipedia.org/wiki/Nucleic_acid_secondary_structure) diagrams in consistent, reproducible and recongnisable layouts using a library of templates representing a wide range of RNAs. +[R2DT](https://r2dt.bio/) automatically generates [RNA secondary structure](https://en.wikipedia.org/wiki/Nucleic_acid_secondary_structure) diagrams in **consistent, reproducible and recongnisable layouts** using a library of templates representing a wide range of RNAs. ## Examples @@ -14,17 +14,20 @@ The following example visualisations show LSU, SSU, and 5S rRNA, four tRNAs, two ## Getting started -R2DT can be used in a number of ways: +R2DT can be used in multiple ways: -* [Web application](https://rnacentral.org/r2dt) hosted by RNAcentral +* Web application at [r2dt.bio](https://r2dt.bio) or in [RNAcentral](https://rnacentral.org/r2dt) * [API](https://www.ebi.ac.uk/Tools/common/tools/help/index.html?tool=r2dt) powered by EMBL-EBI Web Services * As a command line tool with [Docker](https://www.docker.com), [Singularity](https://sylabs.io/docs/#singularity), or in a bare metal installation -You can also [![open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/RNAcentral/R2DT) +[![open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/RNAcentral/R2DT) -## Citation +## 📄 Citation -If you use R2DT in your work, please consider citing the following paper: +If you use R2DT in your work, please cite one of the following papers: + +> **R2DT: a comprehensive platform for visualizing RNA secondary structure** +> [Nucleic Acids Research](https://academic.oup.com/nar/article/53/4/gkaf032/8005627) > **R2DT is a framework for predicting and visualising RNA secondary structure using templates** > [Nature Communications](https://www.nature.com/articles/s41467-021-23555-5) From 25a40bdbd4d343961d8279e525094f7ed7771866 Mon Sep 17 00:00:00 2001 From: Anton Petrov Date: Mon, 10 Feb 2025 16:31:13 +0000 Subject: [PATCH 06/15] Add R2DT NAR image for the timeline --- docs/images/r2dt-nar.png | Bin 0 -> 152695 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/images/r2dt-nar.png diff --git a/docs/images/r2dt-nar.png b/docs/images/r2dt-nar.png new file mode 100644 index 0000000000000000000000000000000000000000..227f34ec4d4ade9632ad2ef1195b63ca27e4323f GIT binary patch literal 152695 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 Date: Sat, 15 Mar 2025 21:56:38 +0000 Subject: [PATCH 07/15] Update year in docs --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index a3c03aa86..4566d4d3f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -9,7 +9,7 @@ # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information project = "R2DT" -copyright = "2023" +copyright = "2025" author = "R2DT Team" # -- General configuration --------------------------------------------------- From 4a0be6f690b2c9d9f35841bda91edb18ce327bc5 Mon Sep 17 00:00:00 2001 From: Anton Petrov Date: Thu, 1 May 2025 11:14:55 +0000 Subject: [PATCH 08/15] refactor: replace os and glob with pathlib for better path handling in generate_model_info.py Co-authored-by: Genie --- utils/generate_model_info.py | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/utils/generate_model_info.py b/utils/generate_model_info.py index 8f06fbc47..b29a0fe75 100644 --- a/utils/generate_model_info.py +++ b/utils/generate_model_info.py @@ -12,10 +12,9 @@ """ -import glob -import os import re import shutil +from pathlib import Path from . import rfam @@ -23,20 +22,21 @@ def allowed_names(cm_library): """Return all model names and CM paths for a given template library.""" - for cm_file in glob.glob(os.path.join(cm_library, "*.cm")): + cm_library = Path(cm_library) + for cm_file in cm_library.glob("*.cm"): model_name = None - if "all.cm" in cm_file: + if cm_file.name == "all.cm": continue - if re.search(r"RF\d{5}", cm_file): - rfam_acc = os.path.basename(cm_file).replace(".cm", "") + if re.search(r"RF\d{5}", str(cm_file)): + rfam_acc = cm_file.stem # removes .cm if rfam_acc in rfam.BLACKLIST: continue - with open(cm_file, "r", encoding="utf-8") as f_cm: + with cm_file.open("r", encoding="utf-8") as f_cm: for line in f_cm: if line.startswith("NAME "): model_name = line.strip().split()[-1] else: - model_name = os.path.basename(cm_file).replace(".cm", "") + model_name = cm_file.stem if not model_name: raise ValueError(f"Could not find model_name for {cm_file}") yield (model_name, cm_file) @@ -45,21 +45,22 @@ def allowed_names(cm_library): def generate_model_info(cm_library, rna_type="SSU"): """Generate a model info file listing all covariance models for a given template library.""" - if not os.path.exists(cm_library): - raise ValueError("Missing CM directory: " + cm_library) + cm_library = Path(cm_library) + if not cm_library.exists(): + raise ValueError("Missing CM directory: " + str(cm_library)) print(f"Processing files in {cm_library}") - all_cm_path = os.path.join(cm_library, "all.cm") - modelinfo = os.path.join(cm_library, "modelinfo.txt") + all_cm_path = cm_library / "all.cm" + modelinfo = cm_library / "modelinfo.txt" - with open(all_cm_path, "w", encoding="utf-8") as all_out: - with open(modelinfo, "w", encoding="utf-8") as model_out: + with all_cm_path.open("w", encoding="utf-8") as all_out: + with modelinfo.open("w", encoding="utf-8") as model_out: model_out.write("*all* - - all.cm\n") for model_name, cm_path in allowed_names(cm_library): - with open(cm_path, "r", encoding="utf-8") as cm_file: + with cm_path.open("r", encoding="utf-8") as cm_file: shutil.copyfileobj(cm_file, all_out) model_line = " ".join( - [model_name, rna_type, "Bacteria", os.path.basename(cm_path)] + [model_name, rna_type, "Bacteria", cm_path.name] ) model_out.write(f"{model_line}\n") print("Done") From 08b3a2617077d0734c0bd95c2b97b6c574633a89 Mon Sep 17 00:00:00 2001 From: Anton Petrov Date: Thu, 1 May 2025 12:05:41 +0000 Subject: [PATCH 09/15] refactor: replace os.path with pathlib for better path handling Co-authored-by: Genie --- r2dt.py | 179 ++++++++++++++++++++--------------- utils/generate_cm_library.py | 15 ++- 2 files changed, 111 insertions(+), 83 deletions(-) diff --git a/r2dt.py b/r2dt.py index 7c70d4baa..0198110df 100755 --- a/r2dt.py +++ b/r2dt.py @@ -13,7 +13,6 @@ limitations under the License. """ # pylint: disable=too-many-lines -import glob import json import os import re @@ -23,6 +22,9 @@ import unittest from pathlib import Path + + + import click # pylint: disable=import-error from rich import print as rprint @@ -84,44 +86,50 @@ def setup(): Generate all templates from scratch. """ rprint(shared.get_r2dt_version_header()) - if not os.path.exists(config.CM_LIBRARY): - os.makedirs(config.CM_LIBRARY) + cm_library = Path(config.CM_LIBRARY) + if not cm_library.exists(): + cm_library.mkdir(parents=True) crw_setup() rfam.setup() gtrnadb.setup() + def crw_setup(): """Setup CRW CM library.""" - if os.path.exists(config.CRW_CM_LIBRARY): + crw_cm_library = Path(config.CRW_CM_LIBRARY) + if crw_cm_library.exists(): rprint("Deleting old CRW library") - shutil.rmtree(config.CRW_CM_LIBRARY) + shutil.rmtree(crw_cm_library) # Extract the tar.gz file rprint("Extracting precomputed CRW archive") - with tarfile.open(os.path.join(config.DATA, "crw-cms.tar.gz"), "r:gz") as tar: + with tarfile.open(Path(config.DATA) / "crw-cms.tar.gz", "r:gz") as tar: tar.extractall(path=config.DATA) # Move the directory - source_dir = os.path.join(config.DATA, "crw-cms") - destination_dir = os.path.join(config.CM_LIBRARY, "crw") + source_dir = Path(config.DATA) / "crw-cms" + destination_dir = Path(config.CM_LIBRARY) / "crw" + + if source_dir.exists(): + shutil.move(str(source_dir), str(destination_dir)) - if os.path.exists(source_dir): - shutil.move(source_dir, destination_dir) # read CRW blacklist crw_blacklist = [] - with open(os.path.join(config.DATA, "crw-blacklist.txt")) as f_in: + with open(Path(config.DATA) / "crw-blacklist.txt") as f_in: for line in f_in: if line.startswith("#"): continue crw_blacklist.append(line.strip()) + # Delete models from the blacklist for model in crw_blacklist: - model_file = os.path.join(config.CRW_CM_LIBRARY, model + ".cm") - if os.path.exists(model_file): - os.remove(model_file) + model_file = Path(config.CRW_CM_LIBRARY) / f"{model}.cm" + if model_file.exists(): + model_file.unlink() + rprint("Generating CRW modelinfo file") gmi.generate_model_info(cm_library=config.CRW_CM_LIBRARY) @@ -160,15 +168,16 @@ def get_hits(folder): Get a list of sequence ids found in the hits.txt file by ribovore. """ hits = set() - hits_file = os.path.join(folder, "hits.txt") - if not os.path.exists(hits_file): + hits_file = Path(folder) / "hits.txt" + if not hits_file.exists(): return hits - with open(hits_file) as f_in: + with hits_file.open() as f_in: for line in f_in: hits.add(line.split("\t")[0]) return hits + def get_subset_fasta(fasta_input, output_filename, seq_ids): """ Extract a fasta file named with sequence ids @@ -180,7 +189,8 @@ def get_subset_fasta(fasta_input, output_filename, seq_ids): f_out.write(f"{seq_id}\n") runner.run(f"esl-sfetch -o {output_filename} -f {fasta_input} {index_filename}") runner.run(f"esl-sfetch --index {output_filename}") - os.remove(index_filename) + Path(index_filename).unlink() + def is_templatefree(fasta_input): @@ -271,31 +281,34 @@ def draw( ) return - os.makedirs(output_folder, exist_ok=True) - crw_output = os.path.join(output_folder, "crw") - ribovision_ssu_output = os.path.join(output_folder, "ribovision-ssu") - ribovision_lsu_output = os.path.join(output_folder, "ribovision-lsu") - rfam_output = os.path.join(output_folder, "rfam") - gtrnadb_output = os.path.join(output_folder, "gtrnadb") - rfam_trna_output = os.path.join(output_folder, "RF00005") - rnasep_output = os.path.join(output_folder, "rnasep") - tmrna_output = os.path.join(output_folder, "tmrna") + output_folder = Path(output_folder) + output_folder.mkdir(exist_ok=True, parents=True) + crw_output = output_folder / "crw" + ribovision_ssu_output = output_folder / "ribovision-ssu" + ribovision_lsu_output = output_folder / "ribovision-lsu" + rfam_output = output_folder / "rfam" + gtrnadb_output = output_folder / "gtrnadb" + rfam_trna_output = output_folder / "RF00005" + rnasep_output = output_folder / "rnasep" + tmrna_output = output_folder / "tmrna" hits = set() - subset_fasta = os.path.join(output_folder, "subset.fasta") + subset_fasta = output_folder / "subset.fasta" runner.run(f"esl-sfetch --index {fasta_input}") + def get_output_subfolder(method_name): """Get folder within the output folder for a given method.""" subfolders = { - "ribovision_draw_ssu": os.path.join(output_folder, "ribovision-ssu"), - "ribovision_draw_lsu": os.path.join(output_folder, "ribovision-lsu"), - "rrna_draw": os.path.join(output_folder, "crw"), - "rnasep_draw": os.path.join(output_folder, "rnasep"), - "tmrna_draw": os.path.join(output_folder, "tmrna"), + "ribovision_draw_ssu": output_folder / "ribovision-ssu", + "ribovision_draw_lsu": output_folder / "ribovision-lsu", + "rrna_draw": output_folder / "crw", + "rnasep_draw": output_folder / "rnasep", + "tmrna_draw": output_folder / "tmrna", } return subfolders.get(str(method_name), "") + method_list = [ "rnasep_draw", "tmrna_draw", @@ -426,59 +439,69 @@ def get_output_subfolder(method_name): organise_metadata(output_folder, result_folders) # clean up - os.system(f"rm {output_folder}/subset*") - os.system(f"rm -f {fasta_input}.ssi") + # Remove subset* files from output_folder + for file in output_folder.glob("subset*"): + file.unlink() + # Remove .ssi index file if it exists + ssi_file = Path(f"{fasta_input}.ssi") + if ssi_file.exists(): + ssi_file.unlink() + def organise_results(results_folder, output_folder): """Move files to the final folder structure.""" folders = {} labels = ["svg", "fasta", "json", "thumbnail"] - destination = os.path.join(output_folder, "results") + destination = Path(output_folder) / "results" for label in labels: - folders[label] = os.path.join(destination, label) - os.makedirs(folders[label], exist_ok=True) - svgs = glob.glob(os.path.join(results_folder, "*.svg")) + folders[label] = destination / label + folders[label].mkdir(parents=True, exist_ok=True) + svgs = list(Path(results_folder).glob("*.svg")) if not svgs: return + for svg in svgs: - if "colored" not in svg: + svg_path = Path(svg) + if "colored" not in str(svg_path): continue - if "enriched" in svg: + if "enriched" in str(svg_path): continue - with open(svg) as f_svg: - thumbnail = shared.generate_thumbnail(f_svg.read(), svg) - thumbnail_filename = svg.replace(".colored.", ".thumbnail.") + with svg_path.open() as f_svg: + thumbnail = shared.generate_thumbnail(f_svg.read(), str(svg_path)) + thumbnail_filename = str(svg_path).replace(".colored.", ".thumbnail.") with open(thumbnail_filename, "w") as f_thumbnail: f_thumbnail.write(thumbnail) results_path = Path(results_folder) + # Move .thumbnail.svg files for file in results_path.glob("*.thumbnail.svg"): - shutil.copy(str(file), folders["thumbnail"]) + shutil.copy(str(file), str(folders["thumbnail"])) file.unlink() # Move .colored.svg files for file in results_path.glob("*.colored.svg"): - shutil.copy(str(file), folders["svg"]) + shutil.copy(str(file), str(folders["svg"])) file.unlink() # Move .enriched.svg files for file in results_path.glob("*.enriched.svg"): - shutil.copy(str(file), folders["svg"]) + shutil.copy(str(file), str(folders["svg"])) file.unlink() # Move .fasta files for file in results_path.glob("*.fasta"): - shutil.copy(str(file), folders["fasta"]) + shutil.copy(str(file), str(folders["fasta"])) file.unlink() # Move .json files for file in results_path.glob("*.json"): - shutil.copy(str(file), folders["json"]) + shutil.copy(str(file), str(folders["json"])) file.unlink() + @cli.group("gtrnadb") def gtrnadb_group(): """ @@ -530,7 +553,8 @@ def gtrnadb_draw( # pylint: disable=too-many-arguments if not quiet: rprint(shared.get_r2dt_version_header()) - os.makedirs(output_folder, exist_ok=True) + Path(output_folder).mkdir(parents=True, exist_ok=True) + fasta_input = shared.sanitise_fasta(fasta_input) @@ -599,7 +623,8 @@ def rnasep_draw( # pylint: disable=too-many-arguments if not quiet: rprint(shared.get_r2dt_version_header()) - os.makedirs(output_folder, exist_ok=True) + Path(output_folder).mkdir(parents=True, exist_ok=True) + fasta_input = shared.sanitise_fasta(fasta_input) @@ -662,7 +687,8 @@ def tmrna_draw( # pylint: disable=too-many-arguments if not quiet: rprint(shared.get_r2dt_version_header()) - os.makedirs(output_folder, exist_ok=True) + Path(output_folder).mkdir(parents=True, exist_ok=True) + with open( shared.get_ribotyper_output( fasta_input, output_folder, config.TMRNA_CM_LIBRARY, skip_ribovore_filters @@ -721,7 +747,8 @@ def rrna_draw( # pylint: disable=too-many-arguments if not quiet: rprint(shared.get_r2dt_version_header()) - os.makedirs(output_folder, exist_ok=True) + Path(output_folder).mkdir(parents=True, exist_ok=True) + fasta_input = shared.sanitise_fasta(fasta_input) @@ -784,7 +811,8 @@ def ribovision_draw_lsu( # pylint: disable=too-many-arguments if not quiet: rprint(shared.get_r2dt_version_header()) - os.makedirs(output_folder, exist_ok=True) + Path(output_folder).mkdir(parents=True, exist_ok=True) + fasta_input = shared.sanitise_fasta(fasta_input) @@ -843,7 +871,8 @@ def ribovision_draw_ssu( # pylint: disable=too-many-arguments if not quiet: rprint(shared.get_r2dt_version_header()) - os.makedirs(output_folder, exist_ok=True) + Path(output_folder).mkdir(parents=True, exist_ok=True) + fasta_input = shared.sanitise_fasta(fasta_input) @@ -966,36 +995,38 @@ def organise_metadata(output_folder, result_folders): """ Aggregate hits.txt files from all subfolders. """ - tsv_folder = os.path.join(output_folder, "results", "tsv") - os.makedirs(tsv_folder, exist_ok=True) - with open(os.path.join(tsv_folder, "metadata.tsv"), "w") as f_out: + tsv_folder = Path(output_folder) / "results" / "tsv" + tsv_folder.mkdir(parents=True, exist_ok=True) + with (tsv_folder / "metadata.tsv").open("w") as f_out: for folder in result_folders: - hits = os.path.join(folder, "hits.txt") - if not os.path.exists(hits): + hits = Path(folder) / "hits.txt" + if not hits.exists(): continue - with open(hits) as f_hits: + with hits.open() as f_hits: for line in f_hits.readlines(): - if "gtrnadb" in folder: + folder_str = str(folder) # since folder is Path or str + if "gtrnadb" in folder_str: line = line.replace("PASS", "GtRNAdb") - elif "crw" in folder: + elif "crw" in folder_str: line = line.replace("PASS", "CRW").replace("FAIL", "CRW") - elif "rfam" in folder or "RF00005" in folder: + elif "rfam" in folder_str or "RF00005" in folder_str: line = line.replace("PASS", "Rfam").replace("FAIL", "Rfam") - elif "ribovision-lsu" in folder or "ribovision-ssu" in folder: + elif "ribovision-lsu" in folder_str or "ribovision-ssu" in folder_str: line = line.replace("PASS", "RiboVision").replace( "FAIL", "RiboVision" ) - elif "rnasep" in folder: + elif "rnasep" in folder_str: line = line.replace("PASS", "RNAse P Database").replace( "FAIL", "RNAse P Database" ) - elif "tmrna" in folder: + elif "tmrna" in folder_str: line = line.replace("PASS", "tmRNA Database").replace( "FAIL", "tmRNA Database" ) f_out.write(line) + @cli.command() @click.argument("cm_library", type=click.Path()) def generatemodelinfo(cm_library): @@ -1081,9 +1112,9 @@ def force_draw( ) # organise results into folders organise_results(output, output_folder) - metadata_folder = os.path.join(output_folder, "results", "tsv") - if not os.path.exists(metadata_folder): - os.makedirs(metadata_folder) + metadata_folder = Path(output_folder) / "results" / "tsv" + if not metadata_folder.exists(): + metadata_folder.mkdir(parents=True) label_mapping = { "crw": "CRW", "gtrnadb": "GtRNAdb", @@ -1094,13 +1125,12 @@ def force_draw( "tmrna": "tmRNA database", "local_data": "Local data", } - with open( - os.path.join(metadata_folder, "metadata.tsv"), "a", encoding="utf-8" - ) as f_out: + with (metadata_folder / "metadata.tsv").open("a", encoding="utf-8") as f_out: line = f"{seq_id}\t{model_id}\t{label_mapping[model_type]}\n" f_out.write(line) + @cli.command() @click.argument("fasta-input", type=click.Path()) @click.argument("output-folder", type=click.Path()) @@ -1191,10 +1221,11 @@ def list_models(): for item in data: rprint(item["description"]) lm.check_unique_descriptions(data) - with open(os.path.join(config.DATA, "models.json"), "w") as models_file: + with (Path(config.DATA) / "models.json").open("w") as models_file: json.dump(data, models_file) + @cli.command() @click.argument("test_name", required=False, default=None, type=click.STRING) def test(test_name): diff --git a/utils/generate_cm_library.py b/utils/generate_cm_library.py index 374df601c..749631845 100644 --- a/utils/generate_cm_library.py +++ b/utils/generate_cm_library.py @@ -11,7 +11,6 @@ limitations under the License. """ -import os import subprocess import tempfile from pathlib import Path @@ -24,7 +23,7 @@ def convert_bpseq_to_fasta(bpseq): """Use a Traveler script to convert from BPSEQ to FASTA.""" fasta = bpseq.replace(".bpseq", ".fasta") - if not os.path.exists(fasta): + if not Path(fasta).exists(): runner.run(f"python /rna/traveler/utils/bpseq2fasta.py -i {bpseq} -o {fasta}") return fasta @@ -32,7 +31,7 @@ def convert_bpseq_to_fasta(bpseq): def break_pseudoknots(fasta): """Remove pseudoknots using RNAStructure.""" fasta_no_knots = fasta.replace("-with-knots.fasta", ".fasta") - if not os.path.exists(fasta_no_knots): + if not Path(fasta_no_knots).exists(): runner.run(f"RemovePseudoknots -b {fasta} {fasta_no_knots}") return fasta_no_knots @@ -40,8 +39,8 @@ def break_pseudoknots(fasta): def convert_fasta_to_stockholm(fasta): """Convert fasta to stockholm.""" stockholm = fasta.replace(".fasta", ".sto") - model_id = os.path.basename(stockholm).replace(".sto", "") - if not os.path.exists(stockholm): + model_id = Path(stockholm).stem + if not Path(stockholm).exists(): with open(fasta, "r", encoding="utf-8") as f_input: with open(stockholm, "w", encoding="utf-8") as f_output: lines = f_input.readlines() @@ -86,10 +85,8 @@ def copy_cm_evalues(cm_filename): def build_cm(stockholm, cm_library): """Build an Infernal covariance model.""" - cm_filename = os.path.join( - cm_library, os.path.basename(stockholm).replace(".sto", ".cm") - ) - if not os.path.exists(cm_filename): + cm_filename = str(Path(cm_library) / (Path(stockholm).stem + ".cm")) + if not Path(cm_filename).exists(): runner.run(f"cmbuild {cm_filename} {stockholm}") copy_cm_evalues(cm_filename) else: From 6add63090889850b2a95fff28c56abc62727d6d9 Mon Sep 17 00:00:00 2001 From: Anton Petrov Date: Thu, 1 May 2025 17:53:30 +0000 Subject: [PATCH 10/15] refactor: update path handling in config.py to use pathlib for better readability and maintainability Co-authored-by: Genie --- utils/config.py | 84 ++++++++++++++++++++++++------------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/utils/config.py b/utils/config.py index 7b10cf246..45080396e 100644 --- a/utils/config.py +++ b/utils/config.py @@ -11,45 +11,45 @@ limitations under the License. """ -import os - -here = os.path.realpath(os.path.dirname(__file__)) -PROJECT_HOME = os.path.dirname(here) -DATA = os.path.join(PROJECT_HOME, "data") - -CRW_CM_LIBRARY = os.path.join(DATA, "cms", "crw") -CRW_PS_LIBRARY = os.path.join(DATA, "crw-ps") -CRW_BPSEQ_LOCATION = os.path.join(DATA, "crw-bpseq") -CRW_FASTA_LIBRARY = os.path.join(DATA, "crw-fasta-no-pseudoknots") - -RFAM_DATA = os.path.join(DATA, "rfam") - -RIBOVISION_LSU = os.path.join(DATA, "ribovision-lsu") -RIBOVISION_SSU = os.path.join(DATA, "ribovision-ssu") -RIBOVISION_LSU_CM_LIBRARY = os.path.join(RIBOVISION_LSU, "cms") -RIBOVISION_SSU_CM_LIBRARY = os.path.join(RIBOVISION_SSU, "cms") -RIBOVISION_LSU_BPSEQ = os.path.join(RIBOVISION_LSU, "bpseq") -RIBOVISION_SSU_BPSEQ = os.path.join(RIBOVISION_SSU, "bpseq") -RIBOVISION_LSU_TRAVELER = os.path.join(RIBOVISION_LSU, "traveler") -RIBOVISION_SSU_TRAVELER = os.path.join(RIBOVISION_SSU, "traveler") - -RNASEP = os.path.join(DATA, "rnasep") -RNASEP_CM_LIBRARY = os.path.join(RNASEP, "cms") -RNASEP_BPSEQ = os.path.join(RNASEP, "bpseq") -RNASEP_TRAVELER = os.path.join(RNASEP, "traveler") - -TMRNA = os.path.join(DATA, "tmrna") -TMRNA_CM_LIBRARY = os.path.join(TMRNA, "cm") -TMRNA_FASTA_LIBRARY = os.path.join(TMRNA, "fasta") -TMRNA_STO_LIBRARY = os.path.join(TMRNA, "sto") -TMRNA_XML_LIBRARY = os.path.join(TMRNA, "xml") - -GTRNADB_CM_LIBRARY = os.path.join(DATA, "gtrnadb", "cms") -GTRNADB_EUK = os.path.join(DATA, "gtrnadb", "eukaryota_isotype_specific") -GTRNADB_BACT = os.path.join(DATA, "gtrnadb", "bacteria_isotype_specific") -GTRNADB_ARCH = os.path.join(DATA, "gtrnadb", "archaea_isotype_specific") -GTRNADB_MITO = os.path.join(DATA, "gtrnadb", "vertebrate_mitochondrial") - -CM_LIBRARY = os.path.join(DATA, "cms") - -LOCAL_DATA = os.path.join(DATA, "local_data") +from pathlib import Path + +here = Path(__file__).resolve().parent +PROJECT_HOME = here.parent +DATA = PROJECT_HOME / "data" + +CRW_CM_LIBRARY = DATA / "cms" / "crw" +CRW_PS_LIBRARY = DATA / "crw-ps" +CRW_BPSEQ_LOCATION = DATA / "crw-bpseq" +CRW_FASTA_LIBRARY = DATA / "crw-fasta-no-pseudoknots" + +RFAM_DATA = DATA / "rfam" + +RIBOVISION_LSU = DATA / "ribovision-lsu" +RIBOVISION_SSU = DATA / "ribovision-ssu" +RIBOVISION_LSU_CM_LIBRARY = RIBOVISION_LSU / "cms" +RIBOVISION_SSU_CM_LIBRARY = RIBOVISION_SSU / "cms" +RIBOVISION_LSU_BPSEQ = RIBOVISION_LSU / "bpseq" +RIBOVISION_SSU_BPSEQ = RIBOVISION_SSU / "bpseq" +RIBOVISION_LSU_TRAVELER = RIBOVISION_LSU / "traveler" +RIBOVISION_SSU_TRAVELER = RIBOVISION_SSU / "traveler" + +RNASEP = DATA / "rnasep" +RNASEP_CM_LIBRARY = RNASEP / "cms" +RNASEP_BPSEQ = RNASEP / "bpseq" +RNASEP_TRAVELER = RNASEP / "traveler" + +TMRNA = DATA / "tmrna" +TMRNA_CM_LIBRARY = TMRNA / "cm" +TMRNA_FASTA_LIBRARY = TMRNA / "fasta" +TMRNA_STO_LIBRARY = TMRNA / "sto" +TMRNA_XML_LIBRARY = TMRNA / "xml" + +GTRNADB_CM_LIBRARY = DATA / "gtrnadb" / "cms" +GTRNADB_EUK = DATA / "gtrnadb" / "eukaryota_isotype_specific" +GTRNADB_BACT = DATA / "gtrnadb" / "bacteria_isotype_specific" +GTRNADB_ARCH = DATA / "gtrnadb" / "archaea_isotype_specific" +GTRNADB_MITO = DATA / "gtrnadb" / "vertebrate_mitochondrial" + +CM_LIBRARY = DATA / "cms" + +LOCAL_DATA = DATA / "local_data" From cecac5ca0189369175838fd71dd6084994252ac7 Mon Sep 17 00:00:00 2001 From: Anton Petrov Date: Thu, 1 May 2025 18:06:46 +0000 Subject: [PATCH 11/15] fix: simplify path handling in setup and crw_setup functions Co-authored-by: Genie --- r2dt.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/r2dt.py b/r2dt.py index 0198110df..8dbf6d2c1 100755 --- a/r2dt.py +++ b/r2dt.py @@ -86,9 +86,8 @@ def setup(): Generate all templates from scratch. """ rprint(shared.get_r2dt_version_header()) - cm_library = Path(config.CM_LIBRARY) - if not cm_library.exists(): - cm_library.mkdir(parents=True) + if not config.CM_LIBRARY.exists(): + config.CM_LIBRARY.mkdir(parents=True) crw_setup() rfam.setup() gtrnadb.setup() @@ -97,19 +96,18 @@ def setup(): def crw_setup(): """Setup CRW CM library.""" - crw_cm_library = Path(config.CRW_CM_LIBRARY) - if crw_cm_library.exists(): + if config.CRW_CM_LIBRARY.exists(): rprint("Deleting old CRW library") - shutil.rmtree(crw_cm_library) + shutil.rmtree(config.CRW_CM_LIBRARY) # Extract the tar.gz file rprint("Extracting precomputed CRW archive") - with tarfile.open(Path(config.DATA) / "crw-cms.tar.gz", "r:gz") as tar: + with tarfile.open(config.DATA / "crw-cms.tar.gz", "r:gz") as tar: tar.extractall(path=config.DATA) # Move the directory - source_dir = Path(config.DATA) / "crw-cms" - destination_dir = Path(config.CM_LIBRARY) / "crw" + source_dir = config.DATA / "crw-cms" + destination_dir = config.CM_LIBRARY / "crw" if source_dir.exists(): shutil.move(str(source_dir), str(destination_dir)) @@ -117,7 +115,7 @@ def crw_setup(): # read CRW blacklist crw_blacklist = [] - with open(Path(config.DATA) / "crw-blacklist.txt") as f_in: + with open(config.DATA / "crw-blacklist.txt") as f_in: for line in f_in: if line.startswith("#"): continue @@ -126,7 +124,7 @@ def crw_setup(): # Delete models from the blacklist for model in crw_blacklist: - model_file = Path(config.CRW_CM_LIBRARY) / f"{model}.cm" + model_file = config.CRW_CM_LIBRARY / f"{model}.cm" if model_file.exists(): model_file.unlink() From 81a2866802a911850191042b2d55208c7bfdeeb7 Mon Sep 17 00:00:00 2001 From: Anton Petrov Date: Thu, 1 May 2025 18:09:38 +0000 Subject: [PATCH 12/15] refactor: replace os.path with pathlib for better path handling in core.py Co-authored-by: Genie --- utils/core.py | 86 ++++++++++++++++++++++++--------------------------- 1 file changed, 41 insertions(+), 45 deletions(-) diff --git a/utils/core.py b/utils/core.py index bb936af28..04ba08797 100644 --- a/utils/core.py +++ b/utils/core.py @@ -11,7 +11,6 @@ limitations under the License. """ -import os import re from pathlib import Path @@ -100,11 +99,9 @@ def visualise( rprint(f"Visualising {seq_id} with {model_id}") elif domain and isotype and not quiet: rprint(f"Visualising {seq_id} with {domain} {isotype}") - if not os.path.exists(output_folder): - os.makedirs(output_folder) - filename_template = os.path.join( - output_folder, f"{seq_id.replace('/', '_')}_type.txt" - ) + output_folder = Path(output_folder) + output_folder.mkdir(parents=True, exist_ok=True) + filename_template = output_folder / f"{seq_id.replace('/', '_')}_type.txt" if rna_type.lower() == "lsu": cm_library = config.RIBOVISION_LSU_CM_LIBRARY template_layout = config.RIBOVISION_LSU_TRAVELER @@ -130,7 +127,7 @@ def visualise( if not model_id.startswith("RF"): model_id = rfam.get_rfam_acc_by_id(model_id) elif rna_type.lower() == "local_data": - cm_library = os.path.join(config.LOCAL_DATA, model_id) + cm_library = config.LOCAL_DATA / model_id template_layout = cm_library template_structure = cm_library elif rna_type.lower() == "gtrnadb": @@ -139,23 +136,24 @@ def visualise( rprint("Please specify RNA type") return - temp_fasta = filename_template.replace("type", "fasta") - temp_sto = filename_template.replace("type", "sto") - temp_depaired = filename_template.replace("type", "depaired") - temp_stk = filename_template.replace("type", "stk") - temp_stk_original = filename_template.replace("type", "stk_original") - temp_sto_unfiltered = filename_template.replace("type", "sto_unfiltered") - temp_acc_list = filename_template.replace("type", "seed_list") - temp_post_prob = filename_template.replace("type", "post_prob") - temp_pfam_stk = filename_template.replace("type", "pfam_stk") - temp_pfam_stk_original = filename_template.replace("type", "pfam_stk_original") - temp_afa = filename_template.replace("type", "afa") - temp_afa_original = filename_template.replace("type", "afa_original") - temp_map = filename_template.replace("type", "map") + # NOTE: filename_template is a Path, so replace returns a str! + temp_fasta = str(filename_template).replace("type", "fasta") + temp_sto = str(filename_template).replace("type", "sto") + temp_depaired = str(filename_template).replace("type", "depaired") + temp_stk = str(filename_template).replace("type", "stk") + temp_stk_original = str(filename_template).replace("type", "stk_original") + temp_sto_unfiltered = str(filename_template).replace("type", "sto_unfiltered") + temp_acc_list = str(filename_template).replace("type", "seed_list") + temp_post_prob = str(filename_template).replace("type", "post_prob") + temp_pfam_stk = str(filename_template).replace("type", "pfam_stk") + temp_pfam_stk_original = str(filename_template).replace("type", "pfam_stk_original") + temp_afa = str(filename_template).replace("type", "afa") + temp_afa_original = str(filename_template).replace("type", "afa_original") + temp_map = str(filename_template).replace("type", "map") # get sequence from fasta file seq_range = f"-c {start}..{end}" if start and end else "" - if not os.path.exists(f"{fasta_input}.ssi"): + if not Path(f"{fasta_input}.ssi").exists(): runner.run(f"esl-sfetch --index {fasta_input}") cmd = f"esl-sfetch {seq_range} {fasta_input} {seq_id} > {temp_fasta}" result = runner.run(cmd) @@ -179,25 +177,25 @@ def visualise( template_layout = gtrnadb.get_traveler_template_xml(domain, isotype) template_structure = gtrnadb.get_traveler_fasta(domain, isotype) elif rna_type == "local_data": - model_path = os.path.join(config.LOCAL_DATA, model_id, model_id + ".cm") - if not os.path.exists(model_path): + model_path = config.LOCAL_DATA / model_id / f"{model_id}.cm" + if not model_path.exists(): rprint(f"Model not found {model_path}") return - template_layout = os.path.join(template_layout, model_id + ".xml") - template_structure = os.path.join(template_structure, model_id + ".fasta") - template_sto = os.path.join(cm_library, model_id + ".sto") + template_layout = template_layout / f"{model_id}.xml" + template_structure = template_structure / f"{model_id}.fasta" + template_sto = cm_library / f"{model_id}.sto" cmd = f"esl-alistat --list {temp_acc_list} {template_sto} > /dev/null" runner.run(cmd) elif rna_type == "tmrna": - model_path = os.path.join(cm_library, model_id + ".cm") - template_layout = os.path.join(template_layout, model_id + ".xml") - template_structure = os.path.join(template_structure, model_id + ".fasta") - template_sto = os.path.join(template_sto, model_id + ".sto") + model_path = cm_library / f"{model_id}.cm" + template_layout = template_layout / f"{model_id}.xml" + template_structure = template_structure / f"{model_id}.fasta" + template_sto = template_sto / f"{model_id}.sto" cmd = f"esl-alistat --list {temp_acc_list} {template_sto} > /dev/null" runner.run(cmd) else: - model_path = os.path.join(cm_library, model_id + ".cm") - if not os.path.exists(model_path): + model_path = cm_library / f"{model_id}.cm" + if not model_path.exists(): rprint(f"Model not found {model_path}") return @@ -319,14 +317,9 @@ def visualise( infernal_mapping_failed = runner.run(cmd) if rna_type == "gtrnadb": - result_base = os.path.join( - output_folder, seq_id.replace("/", "-") + "-" + domain + "_" + isotype - ) + result_base = output_folder / f"{seq_id.replace('/', '-')}-{domain}_{isotype}" else: - result_base = os.path.join( - output_folder, - f"{seq_id.replace('/', '_')}-{model_id}", - ) + result_base = output_folder / f"{seq_id.replace('/', '_')}-{model_id}" # convert stockholm to fasta with dot bracket secondary structure cmd = f"ali-pfam-sindi2dot-bracket.pl {temp_pfam_stk} > {result_base}.fasta" @@ -413,8 +406,9 @@ def visualise( out.write(f"{overlaps}\n") # add metadata to json file - result_json = result_base + ".colored.json" - if os.path.exists(result_json) and os.path.getsize(result_json) > 0: + result_json = str(result_base) + ".colored.json" + result_json_path = Path(result_json) + if result_json_path.exists() and result_json_path.stat().st_size > 0: cmd = ( f"python3 /rna/traveler/utils/enrich_json.py --input-json {result_base}.colored.json " f"--input-data {temp_post_prob} --output {result_base}.enriched.json" @@ -449,8 +443,9 @@ def visualise( temp_acc_list, ] for filename in files: - if os.path.exists(filename): - os.remove(filename) + file_path = Path(filename) + if file_path.exists(): + file_path.unlink() def adjust_font_size(result_base): @@ -494,9 +489,10 @@ def visualise_trna( ): """A wrapper for visualising multiple tRNA sequences in a FASTA file.""" filename = "headers.txt" - os.makedirs(output_folder, exist_ok=True) + output_folder = Path(output_folder) + output_folder.mkdir(parents=True, exist_ok=True) - if not os.path.exists(f"{fasta_input}.ssi"): + if not Path(f"{fasta_input}.ssi").exists(): cmd = f"esl-sfetch --index {fasta_input}" runner.run(cmd) From 0dddf74f0c87a4d817e5060674a8d4a903aab169 Mon Sep 17 00:00:00 2001 From: Anton Petrov Date: Thu, 1 May 2025 18:17:02 +0000 Subject: [PATCH 13/15] refactor: replace os.path with pathlib for path handling in rfam.py Co-authored-by: Genie --- utils/rfam.py | 129 +++++++++++++++++++++++++++++--------------------- 1 file changed, 76 insertions(+), 53 deletions(-) diff --git a/utils/rfam.py b/utils/rfam.py index 768164a58..ddeec4a85 100755 --- a/utils/rfam.py +++ b/utils/rfam.py @@ -14,12 +14,12 @@ import glob import gzip import io -import os import re import shutil import tempfile from pathlib import Path + import requests from tqdm import tqdm @@ -60,7 +60,7 @@ "RF02544", # Mitochondrion-encoded tmRNA ] -PREFER_RNARTIST_LIST = Path(config.RFAM_DATA) / "prefer_rnartist.txt" +PREFER_RNARTIST_LIST = config.RFAM_DATA / "prefer_rnartist.txt" def blacklisted(): @@ -96,54 +96,59 @@ def get_traveler_template_xml(rfam_acc, method="auto"): def get_traveler_fasta(rfam_acc): """Get a path to a consensus structure FASTA given an Rfam accession.""" - filename = os.path.join(config.RFAM_DATA, rfam_acc, f"{rfam_acc}-traveler.fasta") + filename = config.RFAM_DATA / rfam_acc / f"{rfam_acc}-traveler.fasta" return filename + def get_rfam_cm(rfam_acc): """Get a path to an Rfam covariance model given an accession.""" if rfam_acc == "RF00005": - return os.path.join(config.RFAM_DATA, rfam_acc, rfam_acc + ".cm") - return os.path.join(config.CM_LIBRARY, "rfam", rfam_acc + ".cm") + return config.RFAM_DATA / rfam_acc / f"{rfam_acc}.cm" + return config.CM_LIBRARY / "rfam" / f"{rfam_acc}.cm" + def get_rfam_cms(): """Fetch Rfam covariance models excluding blacklisted models.""" - rfam_cm_location = os.path.join(config.CM_LIBRARY, "rfam") - rfam_whitelisted_cm = os.path.join(rfam_cm_location, "all.cm") + rfam_cm_location = config.CM_LIBRARY / "rfam" + rfam_whitelisted_cm = rfam_cm_location / "all.cm" + print("Deleting old Rfam library") - rfam_cm_path = Path(rfam_cm_location) + rfam_cm_path = rfam_cm_location shutil.rmtree(rfam_cm_path, ignore_errors=True) rfam_cm_path.mkdir(parents=True, exist_ok=True) + print("Downloading Rfam.cm from Rfam FTP") - rfam_cm = os.path.join(config.RFAM_DATA, "Rfam.cm") - rfam_ids = os.path.join(config.RFAM_DATA, "rfam_ids.txt") - if not os.path.exists(rfam_cm): + rfam_cm = config.RFAM_DATA / "Rfam.cm" + rfam_ids = config.RFAM_DATA / "rfam_ids.txt" + if not rfam_cm.exists(): url = "http://ftp.ebi.ac.uk/pub/databases/Rfam/CURRENT/Rfam.cm.gz" - rfam_cm_path = Path(rfam_cm).with_suffix(".gz") + rfam_cm_gz = rfam_cm.with_suffix(".cm.gz") # Download the file response = requests.get(url, stream=True) response.raise_for_status() # Raise an exception for HTTP errors - with rfam_cm_path.open("wb") as out_file: + with rfam_cm_gz.open("wb") as out_file: for chunk in response.iter_content(chunk_size=8192): out_file.write(chunk) # Decompress the file - with gzip.open(rfam_cm_path, "rb") as f_in: - with rfam_cm_path.with_suffix(".cm").open("wb") as f_out: + with gzip.open(rfam_cm_gz, "rb") as f_in: + with rfam_cm.open("wb") as f_out: shutil.copyfileobj(f_in, f_out) - rfam_cm_path.unlink() # Remove the .gz file after decompression + rfam_cm_gz.unlink() # Remove the .gz file after decompression + print("Indexing Rfam.cm") - if not os.path.exists(f"{rfam_cm}.ssi"): + if not (rfam_cm.with_suffix(".cm.ssi")).exists() and not (rfam_cm.with_suffix(".ssi")).exists(): runner.run(f"cmfetch --index {rfam_cm}") print("Get a list of all Rfam ids") - if not os.path.exists(rfam_ids): + if not rfam_ids.exists(): with open(rfam_cm, "r") as infile, open(rfam_ids, "w") as outfile: for line in infile: if line.startswith("ACC RF"): @@ -159,21 +164,23 @@ def get_rfam_cms(): continue print(rfam_acc) runner.run(f"cmfetch {rfam_cm} {rfam_acc} >> {rfam_whitelisted_cm}") - cm_file = os.path.join(rfam_cm_location, f"{rfam_acc}.cm") + cm_file = rfam_cm_location / f"{rfam_acc}.cm" runner.run(f"cmfetch {rfam_cm} {rfam_acc} > {cm_file}") + print("Cleaning up") - rfam_cm_path = Path(rfam_cm) + rfam_cm_path = rfam_cm rfam_cm_ssi_path = rfam_cm_path.with_suffix(".ssi") rfam_cm_path.unlink(missing_ok=True) rfam_cm_ssi_path.unlink(missing_ok=True) + def setup_trna_cm(): """Make sure the RF00005 tRNA model exists as it is used as a fallback for all tRNA models that do not match tRNAScan-SE.""" rfam_acc = "RF00005" - trna_cm_path = Path(config.RFAM_DATA) / rfam_acc / f"{rfam_acc}.cm" + trna_cm_path = config.RFAM_DATA / rfam_acc / f"{rfam_acc}.cm" # Create the directory if it doesn't exist trna_cm_path.parent.mkdir(parents=True, exist_ok=True) @@ -194,14 +201,23 @@ def setup_trna_cm(): def delete_preexisting_rfam_data(): """Delete preexisting Rfam data.""" # delete Rfam cms - rfam_cms = os.path.join(config.CM_LIBRARY, "rfam") - os.system(f"rm -f {rfam_cms}/*.cm") - os.system(f"rm -f {rfam_cms}/modelinfo.txt") + rfam_cms = config.CM_LIBRARY / "rfam" + for cm_file in rfam_cms.glob("*.cm"): + cm_file.unlink(missing_ok=True) + modelinfo = rfam_cms / "modelinfo.txt" + modelinfo.unlink(missing_ok=True) # delete template files - os.system(f"rm -Rf {config.RFAM_DATA}/RF0*") + for rfdir in config.RFAM_DATA.glob("RF0*"): + if rfdir.is_dir(): + shutil.rmtree(rfdir, ignore_errors=True) + else: + rfdir.unlink(missing_ok=True) # delete summary files - os.system(f"rm -Rf {config.RFAM_DATA}/family.txt") - os.system(f"rm -Rf {config.RFAM_DATA}/rfam_ids.txt") + family_txt = config.RFAM_DATA / "family.txt" + family_txt.unlink(missing_ok=True) + rfam_ids = config.RFAM_DATA / "rfam_ids.txt" + rfam_ids.unlink(missing_ok=True) + def setup_rnartist(rerun=False): @@ -231,7 +247,8 @@ def setup(accessions=None) -> None: """Setup Rfam template library.""" delete_preexisting_rfam_data() get_rfam_cms() - mi.generate_model_info(cm_library=os.path.join(config.CM_LIBRARY, "rfam")) + mi.generate_model_info(cm_library=Path(config.CM_LIBRARY) / "rfam") + RfamSeed().download_rfam_seed_archive().get_no_structure_file() if not accessions: accessions = get_all_rfam_acc() @@ -247,6 +264,7 @@ def setup(accessions=None) -> None: os.system(f"cd {config.RFAM_DATA} && ./clean_up_files.sh") + # pylint: disable-next=too-many-branches def generate_traveler_fasta(rfam_acc): """ @@ -263,11 +281,12 @@ def generate_traveler_fasta(rfam_acc): # get a list of alignments seeds = [] - for seed in glob.glob(os.path.join(config.RFAM_DATA, rfam_acc, "*.R2R.sto")): + for seed in glob.glob(str(Path(config.RFAM_DATA) / rfam_acc / "*.R2R.sto")): seeds.append(seed) if len(seeds) != 1: print("Error: unusual number of seed alignments") + with open(seeds[0], "r", encoding="utf-8") as f_seed: for line in f_seed.readlines(): if line.startswith("#=GC SS_cons "): @@ -453,17 +472,18 @@ def run_rscape(rfam_acc, destination): """ rfam_seed = RfamSeed().download_rfam_seed(rfam_acc) rfam_seed_no_pk = remove_pseudoknot_from_ss_cons(rfam_seed) - if not os.path.exists(os.path.join(destination, "rscape.done")): + rscape_done = Path(destination) / "rscape.done" + if not rscape_done.exists(): cmd = "R-scape --outdir {folder} {rfam_seed} && touch {folder}/rscape.done".format( folder=destination, rfam_seed=rfam_seed_no_pk ) runner.run(cmd) # delete any temporary r2r_meta files for filename in glob.glob("*.r2r_meta"): - os.remove(filename) + Path(filename).unlink(missing_ok=True) rscape_svg = None - for svg in glob.glob(os.path.join(destination, "*.svg")): + for svg in glob.glob(str(Path(destination) / "*.svg")): if "R2R.sto.svg" in svg: rscape_svg = svg if not rscape_svg: @@ -471,12 +491,13 @@ def run_rscape(rfam_acc, destination): return rscape_svg + def convert_rscape_svg_to_one_line(rscape_svg, destination): """ Convert R-scape SVG into SVG with 1 line per element. """ # pylint: disable=consider-using-f-string - output = os.path.join(destination, "rscape-one-line.svg") + output = str(Path(destination) / "rscape-one-line.svg") cmd = ( r"perl -0777 -pe 's/\n +fill/ fill/g' {rscape_svg} | " r"perl -0777 -pe 's/\n d=/ d=/g' | " @@ -488,6 +509,7 @@ def convert_rscape_svg_to_one_line(rscape_svg, destination): return output + # pylint: disable=too-many-branches def convert_rscape_svg_to_traveler(rscape_one_line_svg, destination): """ @@ -508,14 +530,15 @@ def convert_rscape_svg_to_traveler(rscape_one_line_svg, destination): xml_header = "\n" xml_footer = "" - traveler_template_svg = os.path.join(destination, "traveler-template.svg") + traveler_template_svg = Path(destination) / "traveler-template.svg" with open(rscape_one_line_svg, "r", encoding="utf-8") as f_in: with open(traveler_template_svg, "w", encoding="utf-8") as f_out: with open( - os.path.join(destination, "traveler-template.xml"), + Path(destination) / "traveler-template.xml", "w", encoding="utf-8", ) as xml_out: + f_out.write(header) xml_out.write(xml_header) @@ -558,12 +581,9 @@ def convert_rscape_svg_to_traveler(rscape_one_line_svg, destination): def rscape2traveler(rfam_acc): """Create a Traveler XML template based on an R-scape consensus 2D layout.""" - destination = os.path.join(config.RFAM_DATA, rfam_acc) - if not os.path.exists(destination): - os.makedirs(destination) - if os.path.exists(get_traveler_fasta(rfam_acc)) and os.path.exists( - get_traveler_template_xml(rfam_acc, "r2r") - ): + destination = config.RFAM_DATA / rfam_acc + destination.mkdir(parents=True, exist_ok=True) + if get_traveler_fasta(rfam_acc).exists() and get_traveler_template_xml(rfam_acc, "r2r").exists(): return rscape_svg = run_rscape(rfam_acc, destination) rscape_one_line_svg = convert_rscape_svg_to_one_line(rscape_svg, destination) @@ -572,6 +592,7 @@ def rscape2traveler(rfam_acc): generate_traveler_fasta(rfam_acc) + # pylint: disable-next=too-many-arguments def generate_2d( rfam_acc, @@ -585,11 +606,10 @@ def generate_2d( ): """Loop over the sequences in fasta file and visualise each using the family template.""" - destination = f"{output_folder}/{rfam_acc}" - if not os.path.exists(destination): - os.makedirs(destination) + destination = Path(output_folder) / rfam_acc + destination.mkdir(parents=True, exist_ok=True) - if not os.path.exists(fasta_input + ".ssi"): + if not Path(f"{fasta_input}.ssi").exists(): runner.run(f"esl-sfetch --index {fasta_input}") # pylint: disable=consider-using-with headers = tempfile.NamedTemporaryFile(delete=False).name @@ -604,7 +624,7 @@ def generate_2d( core.visualise( "rfam", fasta_input, - destination, + str(destination), seq_id, rfam_acc, constraint, @@ -620,30 +640,32 @@ def generate_2d( Path(headers).unlink(missing_ok=True) + def has_structure(rfam_acc): """Return a list of families that have consensus 2D structure.""" no_structure = [] - no_structure_filename = os.path.join(config.RFAM_DATA, "no_structure.txt") + no_structure_filename = config.RFAM_DATA / "no_structure.txt" with open(no_structure_filename) as f_list: for line in f_list.readlines(): no_structure.append(line.strip()) return rfam_acc not in no_structure + def cmsearch_nohmm_mode(fasta_input, output_folder, rfam_acc): """ Run cmsearch on the fasta sequences using cmsearch in the --nohmm mode to get potentially missing hits. """ - subfolder = os.path.join(output_folder, rfam_acc) - os.makedirs(subfolder, exist_ok=True) - tblout = os.path.join(subfolder, "cmsearch.tblout") - outfile = os.path.join(subfolder, "cmsearch.out.txt") - cm_file = os.path.join(config.RFAM_DATA, rfam_acc, f"{rfam_acc}.cm") + subfolder = Path(output_folder) / rfam_acc + subfolder.mkdir(parents=True, exist_ok=True) + tblout = subfolder / "cmsearch.tblout" + outfile = subfolder / "cmsearch.out.txt" + cm_file = config.RFAM_DATA / rfam_acc / f"{rfam_acc}.cm" runner.run( f"cmsearch --nohmm -o {outfile} --tblout {tblout} {cm_file} {fasta_input}" ) - hits = os.path.join(subfolder, "hits.txt") + hits = subfolder / "hits.txt" with open(tblout, "r") as infile, open(hits, "w") as outfile: for line in infile: if not line.startswith("#") and "?" not in line: @@ -660,3 +682,4 @@ def cmsearch_nohmm_mode(fasta_input, output_folder, rfam_acc): hit_id, _, _ = line.strip().split("\t") ids.add(hit_id) return ids + From 895ff53e34f4e61a6ad70162573cae4e793e0318 Mon Sep 17 00:00:00 2001 From: Anton Petrov Date: Thu, 1 May 2025 18:35:10 +0000 Subject: [PATCH 14/15] refactor: replace os.path with pathlib for better path handling Co-authored-by: Genie --- utils/gtrnadb.py | 52 +++++++++++++++++++++--------------------------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/utils/gtrnadb.py b/utils/gtrnadb.py index 395e91d33..2abbf7af0 100644 --- a/utils/gtrnadb.py +++ b/utils/gtrnadb.py @@ -11,7 +11,6 @@ limitations under the License. """ -import os import re from pathlib import Path @@ -25,7 +24,7 @@ def setup(): """Extract tRNAScan covariance models as separate files.""" - base = os.path.join("usr", "lib", "tRNAscan-SE", "models") + base = Path("usr") / "lib" / "tRNAscan-SE" / "models" cm_dbs = { "TRNAinf-arch-iso": "A", "TRNAinf-bact-iso": "B", @@ -33,7 +32,7 @@ def setup(): "TRNAinf-mito-vert": "M", } for cm_file, domain in cm_dbs.items(): - path = Path(os.path.join(base, cm_file)) + path = base / cm_file with path.open("r", encoding="utf-8") as raw: for line in raw: line = line.strip() @@ -134,14 +133,14 @@ def parse_trnascan_output(filename, domain): def run_trnascan(fasta_input, output_folder, domain): """Launch tRNAScan-SE and return parsed results.""" - output_file = os.path.join(output_folder, f"{domain}-trnascan.txt") - if domain == "M": - domain = "M vert" - if not os.path.exists(output_file): + output_folder = Path(output_folder) + output_file = output_folder / f"{domain}-trnascan.txt" + run_domain = "M vert" if domain == "M" else domain + if not output_file.exists(): runner.run( - f"tRNAscan-SE --detail -c {TRNASCAN_CONF} -q -{domain} -o {output_file} {fasta_input}" + f"tRNAscan-SE --detail -c {TRNASCAN_CONF} -q -{run_domain} -o {output_file} {fasta_input}" ) - return parse_trnascan_output(output_file, domain) + return parse_trnascan_output(output_file, run_domain) def skip_trna(entry): @@ -153,8 +152,8 @@ def skip_trna(entry): def classify_trna_sequences(fasta_input, output_folder): """Run tRNAScan-SE 2.0 and select the matching model.""" - if not os.path.exists(output_folder): - os.mkdir(output_folder) + output_folder = Path(output_folder) + output_folder.mkdir(parents=True, exist_ok=True) mito_vert = run_trnascan(fasta_input, output_folder, "M") bacteria = run_trnascan(fasta_input, output_folder, "B") archaea = run_trnascan(fasta_input, output_folder, "A") @@ -205,7 +204,7 @@ def classify_trna_sequences(fasta_input, output_folder): ) data.append(mito_vert[rna_id]) - with open(os.path.join(output_folder, "hits.txt"), "w", encoding="utf-8") as f_out: + with (output_folder / "hits.txt").open("w", encoding="utf-8") as f_out: for entry in data: f_out.write(f"{entry['id']}\t{entry['domain']}_{entry['isotype']}\tPASS\n") return data @@ -215,9 +214,10 @@ def get_trnascan_cm(domain, isotype): """ Fetch a domain-specific isotype covariance model as a separate file. """ - if not os.path.exists(config.GTRNADB_CM_LIBRARY): - os.mkdir(config.GTRNADB_CM_LIBRARY) - cm_output = Path(config.GTRNADB_CM_LIBRARY) / f"{domain}_{isotype}.cm" + cm_lib = config.GTRNADB_CM_LIBRARY + if not cm_lib.exists(): + cm_lib.mkdir(parents=True, exist_ok=True) + cm_output = cm_lib / f"{domain}_{isotype}.cm" if cm_output.exists(): return str(cm_output) @@ -247,34 +247,28 @@ def get_trnascan_cm(domain, isotype): def get_traveler_template_xml(domain, isotype): """Get Traveler template with coordinates.""" if domain == "A": - return os.path.join( - config.GTRNADB_ARCH, f"arch-{isotype}-traveler-template.xml" - ) + return config.GTRNADB_ARCH / f"arch-{isotype}-traveler-template.xml" if domain == "B": - return os.path.join( - config.GTRNADB_BACT, f"bact-{isotype}-traveler-template.xml" - ) + return config.GTRNADB_BACT / f"bact-{isotype}-traveler-template.xml" if domain == "M": if "Leu" in isotype or "Ser" in isotype: isotype = isotype[0:3] + "_" + isotype[3:6] - return os.path.join( - config.GTRNADB_MITO, f"mito_vert_{isotype}-traveler-template.xml" - ) + return config.GTRNADB_MITO / f"mito_vert_{isotype}-traveler-template.xml" if domain == "E": - return os.path.join(config.GTRNADB_EUK, f"euk-{isotype}-traveler-template.xml") + return config.GTRNADB_EUK / f"euk-{isotype}-traveler-template.xml" raise ValueError(f"Unknown domain {domain}") def get_traveler_fasta(domain, isotype): """Get Traveler structure file.""" if domain == "A": - return os.path.join(config.GTRNADB_ARCH, f"arch-{isotype}-traveler.fasta") + return config.GTRNADB_ARCH / f"arch-{isotype}-traveler.fasta" if domain == "B": - return os.path.join(config.GTRNADB_BACT, f"bact-{isotype}-traveler.fasta") + return config.GTRNADB_BACT / f"bact-{isotype}-traveler.fasta" if domain == "M": if "Leu" in isotype or "Ser" in isotype: isotype = isotype[0:3] + "_" + isotype[3:6] - return os.path.join(config.GTRNADB_MITO, f"mito_vert_{isotype}-traveler.fasta") + return config.GTRNADB_MITO / f"mito_vert_{isotype}-traveler.fasta" if domain == "E": - return os.path.join(config.GTRNADB_EUK, f"euk-{isotype}-traveler.fasta") + return config.GTRNADB_EUK / f"euk-{isotype}-traveler.fasta" raise ValueError(f"Unknown domain {domain}") From 3f9eccfccca82d00e8e98337c9ae034229299a4c Mon Sep 17 00:00:00 2001 From: Anton Petrov Date: Thu, 1 May 2025 18:39:38 +0000 Subject: [PATCH 15/15] fix: update destination path assignment in RnaArtist class Co-authored-by: Genie --- utils/rnartist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/rnartist.py b/utils/rnartist.py index 364108c01..ae372cd7b 100644 --- a/utils/rnartist.py +++ b/utils/rnartist.py @@ -16,7 +16,7 @@ def __init__(self, rfam_acc="rnartist", destination=None) -> None: if destination: self.destination = Path(destination) else: - self.destination = Path(config.RFAM_DATA) / self.rfam_acc + self.destination = config.RFAM_DATA / self.rfam_acc if self.rfam_acc == "rnartist": self.fasta_file = "" else: