{"id":16864755,"url":"https://github.com/38/grass","last_synced_at":"2025-03-22T06:32:35.064Z","repository":{"id":37944309,"uuid":"455284353","full_name":"38/grass","owner":"38","description":null,"archived":false,"fork":false,"pushed_at":"2022-07-28T17:23:47.000Z","size":3386,"stargazers_count":21,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-10-14T14:43:43.389Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/38.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-02-03T18:36:52.000Z","updated_at":"2024-08-05T05:54:42.000Z","dependencies_parsed_at":"2022-07-11T23:48:15.138Z","dependency_job_id":null,"html_url":"https://github.com/38/grass","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/38%2Fgrass","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/38%2Fgrass/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/38%2Fgrass/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/38%2Fgrass/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/38","download_url":"https://codeload.github.com/38/grass/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221824019,"owners_count":16886753,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-13T14:43:44.852Z","updated_at":"2024-10-28T12:09:54.807Z","avatar_url":"https://github.com/38.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# grass\n\n## What is Grass?\n\nGRASS is a genomics data manipulation and analysis system powered by Rust programming language.\n\nGRASS uses python as frontend language and defines a DSL(domain specific language) for genomics data analysis. The DSL then is transcompiled to Rust code and compiled to executable binary. The goal of GRASS is to provide a expressive and fast way to analyze genomics data.\n\n## Installation\n\n### Install with pip\n\nYou can install pygrass from [PyPI](https://pypi.python.org/pypi/pygrass) and use GRASS.\n\n```bash\npip install pygrass\n```\n\n### Use the local build\n\nYou can use the local build of GRASS.\n\n```bash\ngit clone https://github.com/38/grass.git\ncd grass/pygrass\npython3 setup.py build\nexport PYTHONPATH=$PYTHONPATH:$(pwd)/build/lib\nexport GRASS_RUNTIME_PATH=$(pwd)/../grass-runtime\nexport GRASS_MACRO_PATH=$(pwd)/../grass-macro\n```\n\n## Usage by Examples\n\n### 1. Intersection two sorted interval file and print the result to stdout\n\n```python\n    # simple_intersect.py\n\n    import pygrass\n\n    # Open two files\n    file_a = pygrass.IntervalFile(\"file_a.bed\")\n    file_b = pygrass.IntervalFile(\"file_b.bed\")\n\n    # Intersect two files and print\n    file_a.intersect(file_b).print_to_stdout()\n```\n\nYou can simple run this python script and get the result. When you first time run this script,\nyou may experience a long waiting time due to the Rust source code compilation. But the binary artifact is then cached for later use. When you run similar query later, it will find the previously\nbuilt binary artifact and use it. (For example, you change the input file name, then GRASS will pick\nthe previously built binary artifact and use it.)\n\nAlthough this looks like it's a python script, but this python code doesn't actually execute the\noperation. It just captures what operation you want to perform and create a intermediate representation\nfor this operation. To see the operation, you can run the following command:\n\n```bash\n# simple_intersect.py\nGRASS_BACKEND_CLASS=pygrass.backend.DumpIR python3 simple_intersec.py\n```\n\nThis will print the IR of the intersection operation. It may look like this:\n\n```json\n{\n    \"opcode\": \"WriteFile\",\n    \"what\": {\n        \"opcode\": \"Let\",\n        \"id\": \"_grass_res_0\",\n        \"value\": {\n            \"opcode\": \"Intersection\",\n            \"flavor\": \"inner\",\n            \"lhs\": {\n                \"opcode\": \"Let\",\n                \"id\": \"_grass_res_1\",\n                \"value\": {\n                    \"opcode\": \"Open\",\n                    \"target\": {\n                        \"Path\": {\n                            \"const_bag_key\": 0\n                        }\n                    },\n                    \"format\": \"Bed\",\n                    \"num_of_fields\": 3,\n                    \"compression\": false,\n                    \"sorted\": true\n                }\n            },\n            \"rhs\": {\n                \"opcode\": \"Let\",\n                \"id\": \"_grass_res_2\",\n                \"value\": {\n                    \"opcode\": \"Open\",\n                    \"target\": {\n                        \"Path\": {\n                            \"const_bag_key\": 1\n                        }\n                    },\n                    \"format\": \"Bed\",\n                    \"num_of_fields\": 3,\n                    \"compression\": false,\n                    \"sorted\": true\n                }\n            },\n            \"sorted\": true\n        }\n    },\n    \"target\": 1\n}\n```\n\nNote that no actual intersection is performed by Python interpreter.\nThus we are able to see intersection with pygrass runs as fast as native C/C++ code.\n\n## 2. Chaining basic operations\n\nOne of the most powerful feature of GRASS is chainning basic operations.\nUnlike you are chainning command line tools with pipes, in GRASS the chained operations are fused into\na single binary artifact which avoids huge performance overhead by repeatly serializing and deserializing data.\n\nFor example, you can shift the the intervals from file_a.bed and then intersect with file_b.bed.\n\n```python\n    # chaining_intersect.py\n    import pygrass\n\n    # Open two files\n    file_a = pygrass.IntervalFile(\"file_a.bed\")\n    file_b = pygrass.IntervalFile(\"file_b.bed\")\n\n    # Extend intervals from file_a\n    # Note that after the alteration, GRASS doesn't know if the intervals are sorted or not.\n    # Thus, you need to explicitly set the sorted flag to true by calling `assume_sorted` method.\n    extended_file_a = file_a.alter(start = pygrass.start - 50, end = pygrass.end - 50).assume_sorted()\n\n    # Extend intervals from file_a.bed and intersect with file_b.bed\n    extended_file_a.intersect(file_b).print_to_stdout()\n```\n\nThis is equivalent to the following command with bedtools:\n\n```bash\nbedtools shift -s 50 file_a.bed | bedtools intersect -a - -b file_b.bed\n```\n\nUnlike bedtools invocation, pygrass actually generates a problem specific Rust program for the operation.\nYou can see the Rust program by running the following command:\n\n```bash\n# chaining_intersect.py\nGRASS_BACKEND_CLASS=pygrass.backend.DumpRustCode python3 chaining_intersect.py\n```\n\nAnd this will print the Rust code.\n\n```rust\n#![feature(prelude_import)]\n#[prelude_import]\nuse std::prelude::rust_2021::*;\n#[macro_use]\nextern crate std;\n#[allow(unused_imports)]\nuse grass_runtime::const_bag::{ConstBagRef, ConstBagType};\nconst __CONST_BAG_VALUE_0: ConstBagRef\u003cString\u003e = ConstBagRef::\u003cString\u003e::new(0);\nconst __CONST_BAG_VALUE_1: ConstBagRef\u003cf64\u003e = ConstBagRef::\u003cf64\u003e::new(1);\nconst __CONST_BAG_VALUE_2: ConstBagRef\u003cf64\u003e = ConstBagRef::\u003cf64\u003e::new(2);\nconst __CONST_BAG_VALUE_3: ConstBagRef\u003cString\u003e = ConstBagRef::\u003cString\u003e::new(3);\nfn grass_query_0(cmd_args: \u0026[\u0026str]) -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n    let _grass_query_temp_f5ad7a5bff714cd69a4983d46ed7e408 = {\n        use grass_runtime::LineRecordStreamExt;\n        use grass_runtime::algorithm::AssumeSorted;\n        (std::fs::File::open(__CONST_BAG_VALUE_0.value())?)\n            .into_record_iter::\u003cgrass_runtime::record::Bed3\u003e()\n            .assume_sorted()\n    };\n    let _grass_query_temp_b97606781e914e8c808dfe9119dab4a3 = {\n        use grass_runtime::algorithm::AssumeSorted;\n        let ret = _grass_query_temp_f5ad7a5bff714cd69a4983d46ed7e408.map(|mut item| {\n            let new_value = Some(\u0026item)\n                .map(|_arg| {\n                    ({\n                        use grass_runtime::property::*;\n                        _arg.start()\n                    } as f64)\n                        - (__CONST_BAG_VALUE_1.value())\n                })\n                .unwrap();\n            item.set_start(new_value);\n            item\n        });\n        ();\n        ret\n    };\n    let _grass_query_temp_87eecafbfd1d47e9b5030a7e7d9fef8c = {\n        use grass_runtime::algorithm::AssumeSorted;\n        let ret = _grass_query_temp_b97606781e914e8c808dfe9119dab4a3.map(|mut item| {\n            let new_value = Some(\u0026item)\n                .map(|_arg| {\n                    ({\n                        use grass_runtime::property::*;\n                        _arg.end()\n                    } as f64)\n                        - (__CONST_BAG_VALUE_2.value())\n                })\n                .unwrap();\n            item.set_end(new_value);\n            item\n        });\n        ();\n        ret\n    };\n    let _grass_query_temp_20606989ee8041d98cede5a20cb44419 = {\n        use grass_runtime::algorithm::AssumeSorted;\n        _grass_query_temp_87eecafbfd1d47e9b5030a7e7d9fef8c.assume_sorted()\n    };\n    let _grass_query_temp_516296693b3a483298ab5fa7d89828d3 = {\n        use grass_runtime::LineRecordStreamExt;\n        use grass_runtime::algorithm::AssumeSorted;\n        (std::fs::File::open(__CONST_BAG_VALUE_3.value())?)\n            .into_record_iter::\u003cgrass_runtime::record::Bed3\u003e()\n            .assume_sorted()\n    };\n    let _grass_query_temp_bcc301d7add847bca7ae45e58e71f33b = {\n        use grass_runtime::algorithm::SortedIntersect;\n        _grass_query_temp_20606989ee8041d98cede5a20cb44419\n            .sorted_intersect(_grass_query_temp_516296693b3a483298ab5fa7d89828d3)\n    };\n    let _grass_query_temp_9fcad4cdbbe84dd392aed4ba2c15e049 = {\n        #[cfg(unix)]\n        use std::os::unix::io::FromRawFd;\n        use std::io::Write;\n        use grass_runtime::property::Serializable;\n        let mut out_f = std::io::BufWriter::new(unsafe { std::fs::File::from_raw_fd(1i32) });\n        for item in _grass_query_temp_bcc301d7add847bca7ae45e58e71f33b {\n            item.dump(\u0026mut out_f)?;\n            out_f.write_all(b\"\\n\")?;\n        }\n    };\n    Ok(())\n}\nfn main() -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n    let owned_cmd_args: Vec\u003c_\u003e = std::env::args().collect();\n    let cmd_args: Vec\u003c_\u003e = owned_cmd_args.iter().map(|a| a.as_str()).collect();\n    grass_query_0(\u0026cmd_args)?;\n    Ok(())\n}\n```\n\n## Implementing bedtools tutorial with pygrass\n\nThere are example implementations of the functionality of the [bedtools tutorial](http://quinlanlab.org/tutorials/bedtools/bedtools.html) in pygrass available,\nsee [data/bedtools-tutorial](https://github.com/38/grass/tree/master/data/bedtools-tutorial) for details.\n\nTo try these examples, you need to use the latest version of pygrass,\nsee [use the local build](#use-the-local-build) for how to run the examples with the local grass build.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F38%2Fgrass","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F38%2Fgrass","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F38%2Fgrass/lists"}