├── .gitignore ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── README.rst ├── complexCGR.pdf ├── complexcgr ├── __init__.py ├── cgr.py ├── complexcgr.py ├── complexfcgr.py ├── fcgr.py ├── fcgr_kmc.py ├── fcgr_samples.py └── icgr.py ├── img ├── ACG-complexCGR.png ├── ACG.jpg ├── ACG_16bits.jpg ├── CGA.jpg ├── CGAN.jpg ├── SAMD00003784.jpeg ├── SAMD00032020.jpeg ├── SAMD00111209.jpeg ├── SAMD00111306.jpeg ├── complexcgr-readme.png ├── logo-complexCGR-nb.png ├── logo-complexCGR-v2-nb.png ├── logo-complexCGR-v2.png ├── logo-complexCGR-v3-nb.png ├── logo-complexCGR-v3.png └── logo-complexCGR.png ├── poetry.lock ├── pyproject.toml └── tests ├── __init__.py ├── test_cgr.py ├── test_complexcgr.py ├── test_complexfcgr.py ├── test_complexfcgr_savefig.py ├── test_fcgr.py └── test_icgr.py /.gitignore: -------------------------------------------------------------------------------- 1 | # img/ 2 | # Byte-compiled / optimized / DLL files 3 | __pycache__/ 4 | *.py[cod] 5 | *$py.class 6 | env.yml 7 | # C extensions 8 | *.so 9 | 10 | # Distribution / packaging 11 | .Python 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | pip-wheel-metadata/ 25 | share/python-wheels/ 26 | *.egg-info/ 27 | .installed.cfg 28 | *.egg 29 | MANIFEST 30 | 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | *.spec 36 | 37 | # Installer logs 38 | pip-log.txt 39 | pip-delete-this-directory.txt 40 | 41 | # Unit test / coverage reports 42 | htmlcov/ 43 | .tox/ 44 | .nox/ 45 | .coverage 46 | .coverage.* 47 | .cache 48 | nosetests.xml 49 | coverage.xml 50 | *.cover 51 | *.py,cover 52 | .hypothesis/ 53 | .pytest_cache/ 54 | 55 | # Translations 56 | *.mo 57 | *.pot 58 | 59 | # Django stuff: 60 | *.log 61 | local_settings.py 62 | db.sqlite3 63 | db.sqlite3-journal 64 | 65 | # Flask stuff: 66 | instance/ 67 | .webassets-cache 68 | 69 | # Scrapy stuff: 70 | .scrapy 71 | 72 | # Sphinx documentation 73 | docs/_build/ 74 | 75 | # PyBuilder 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | .python-version 87 | 88 | # pipenv 89 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 90 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 91 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 92 | # install all needed dependencies. 93 | #Pipfile.lock 94 | 95 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 96 | __pypackages__/ 97 | 98 | # Celery stuff 99 | celerybeat-schedule 100 | celerybeat.pid 101 | 102 | # SageMath parsed files 103 | *.sage.py 104 | 105 | # Environments 106 | .env 107 | .venv 108 | env/ 109 | venv/ 110 | ENV/ 111 | env.bak/ 112 | venv.bak/ 113 | 114 | # Spyder project settings 115 | .spyderproject 116 | .spyproject 117 | 118 | # Rope project settings 119 | .ropeproject 120 | 121 | # mkdocs documentation 122 | /site 123 | 124 | # mypy 125 | .mypy_cache/ 126 | .dmypy.json 127 | dmypy.json 128 | 129 | # Pyre type checker 130 | .pyre/ 131 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "workbench.colorCustomizations": { 3 | "activityBar.activeBackground": "#65c89b", 4 | "activityBar.activeBorder": "#945bc4", 5 | "activityBar.background": "#65c89b", 6 | "activityBar.foreground": "#15202b", 7 | "activityBar.inactiveForeground": "#15202b99", 8 | "activityBarBadge.background": "#945bc4", 9 | "activityBarBadge.foreground": "#e7e7e7", 10 | "sash.hoverBorder": "#65c89b", 11 | "statusBar.background": "#42b883", 12 | "statusBar.foreground": "#15202b", 13 | "statusBarItem.hoverBackground": "#359268", 14 | "statusBarItem.remoteBackground": "#42b883", 15 | "statusBarItem.remoteForeground": "#15202b", 16 | "titleBar.activeBackground": "#42b883", 17 | "titleBar.activeForeground": "#15202b", 18 | "titleBar.inactiveBackground": "#42b88399", 19 | "titleBar.inactiveForeground": "#15202b99", 20 | "commandCenter.border": "#15202b99" 21 | }, 22 | "peacock.color": "#42b883" 23 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Koke 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # `complexcgr` 4 | This library have classes around the *Chaos Game Representation* for DNA sequence 5 | 6 | **The FCGR helps to visualize a k-mer distribution** The `FCGR` of a sequence is an image showing the distribution of the $k$-mers 7 | given a chosen $k$. The frequencies of all $k$-mers are distributed in the position of a matrix of $2^k \times 2^k$, 8 | which considers all the possible $k$-mers: $4^k$. 9 | 10 | The position that a $k$-mer uses in the matrix depends on the encoding given by the `CGR`. 11 | 12 | Some examples of [bacterial assemblies](https://zenodo.org/records/4602622) ([see reference](https://journals.plos.org/plosbiology/article?id=10.1371/journal.pbio.3001421)) are shown below. 13 | The name of the species and the `sample_id` is in the title of each image ([see an example with the first image](https://www.ebi.ac.uk/ena/browser/view/SAMEA2658585)). These images were 14 | created using the 6-mers of each assembly and the class `FCGR` of this library. 15 | 16 | | ![FCGR of 10 bacteria](img/complexcgr-readme.png) | 17 | |:--:| 18 | |10 different species of bacteria represented by their FCGR (6-mers)| --> 19 | 20 | ## Installation 21 | [pypi](https://pypi.org/project/complexcgr/) 22 | ___ 23 | ```shell 24 | pip install complexcgr 25 | ``` 26 | 27 | to update to the latest version 28 | ```shell 29 | pip install complexcgr --upgrade 30 | ``` 31 | 32 | ## How to use 33 | ___ 34 | ### 1. `CGR` Chaos Game Representation of DNA 35 | ```python 36 | from complexcgr import CGR 37 | 38 | # Instantiate class CGR 39 | cgr = CGR() 40 | 41 | # encode a sequence 42 | cgr.encode("ACGT") 43 | # > CGRCoords(N=4, x=0.1875, y=-0.5625) 44 | 45 | # recover a sequence from CGR coordinates 46 | cgr.decode(N=4,x=0.1875,y=-0.5625) 47 | # > "ACGT" 48 | ``` 49 | 50 | ### 2. `FCGR` Frequency Matrix of Chaos Game Representation of DNA 51 | Input for FCGR only accept sequences in $\{A,C,G,T,N\}$, but all $k$-mers that contains an $N$ 52 | will not be considered for the calculation of the frequency matrix CGR 53 | ```python 54 | import random; random.seed(42) 55 | from complexcgr import FCGR 56 | 57 | # set the k-mer 58 | fcgr = FCGR(k=8) # (256x256) array 59 | 60 | # Generate a random sequence without T's 61 | seq = "".join(random.choice("ACG") for _ in range(300_000)) 62 | chaos = fcgr(seq) # an array with the frequencies of each k-mer 63 | fcgr.plot(chaos) 64 | ``` 65 | | ![FCGR for a sequence without T's](img/CGA.jpg) | 66 | |:--:| 67 | |FCGR representation for a sequence without T's| 68 | 69 | 70 | You can save the image with 71 | ```python 72 | fcgr.save_img(chaos, path="img/ACG.jpg") 73 | ``` 74 | *Formats allowed are defined by PIL.* 75 | 76 | You can also generate the image in 16 (or more bits), to avoid losing information of k-mer frequencies 77 | ```python 78 | # Generate image in 16-bits (default is 8-bits) 79 | fcgr = FCGR(k=8, bits=16) # (256x256) array. When using plot() it will be rescaled to [0,65535] colors 80 | ``` 81 | 82 | 83 | ```python 84 | # Generate a random sequence without T's and lots of N's 85 | seq = "".join(random.choice("ACGN") for _ in range(300_000)) 86 | chaos = fcgr(seq) # an array with the probabilities of each k-mer 87 | fcgr.plot(chaos) 88 | ``` 89 | 90 | 91 | |![FCGR for a sequence without T's](img/CGAN.jpg)| 92 | |:--:| 93 | |FCGR representation for a sequence without T's and lots of N's| 94 | 95 | 96 | 97 | ### 3. `iCGR` integer Chaos Game Representation of DNA 98 | ```python 99 | from complexcgr import iCGR 100 | 101 | # Instantiate class CGR 102 | icgr = iCGR() 103 | 104 | # encode a sequence 105 | icgr.encode("ACGT") 106 | # > CGRCoords(N=4, x=3, y=-9) 107 | 108 | # recover a sequence from CGR coordinates 109 | icgr.decode(N=4,x=3,y=-9) 110 | # > "ACGT" 111 | ``` 112 | 113 | ### 4. `ComplexCGR` Complex Chaos Game Representation of DNA (ComplexCGR) 114 | 115 | ```python 116 | from complexcgr import ComplexCGR 117 | 118 | # Instantiate class CGR 119 | ccgr = ComplexCGR() 120 | 121 | # encode a sequence 122 | ccgr.encode("ACGT") 123 | # > CGRCoords(k=228,N=4) 124 | 125 | # recover a sequence from ComplexCGR coordinates 126 | ccgr.decode(k=228,N=4) 127 | # > "ACGT" 128 | 129 | ``` 130 | 131 | ### 5. `ComplexFCGR` Frequency Matrix of Complex Chaos Game Representation of DNA 132 | Input for FCGR only accept sequences in $\{A,C,G,T,N\}$, but all $k$-mers that contains an $N$ 133 | will not be considered for the calculation of the frequency matrix CGR 134 | ```python 135 | import random; random.seed(42) 136 | from complexcgr import FCGR 137 | 138 | # set the k-mer desired 139 | cfcgr = ComplexFCGR(k=8) # 8-mers 140 | 141 | # Generate a random sequence without T's 142 | seq = "".join(random.choice("ACG") for _ in range(300_000)) 143 | fig = cfcgr(seq) 144 | 145 | ``` 146 | | ![FCGR for a sequence without T's](img/ACG-complexCGR.png) | 147 | |:--:| 148 | |ComplexFCGR representation for a sequence without T's| 149 | 150 | 151 | You can save the image with 152 | ```python 153 | cfcgr.save(fig, path="img/ACG-ComplexCGR.png") 154 | ``` 155 | *Currently the plot must be saved as png* 156 | 157 | ___ 158 | ## Advice for Real applications 159 | 160 | **Count k-mers** could be the bottleneck for large sequences (> 100000 bp). 161 | Note that the class `FCGR` (and `ComplexCGR`) has implemented a naive approach to count k-mers, this is intended since in practice state-of-the-art tools like KMC or Jellyfish are used to count k-mers very efficiently. 162 | 163 | We provide the class `FCGRKmc`, that receives as input the file generated by the following pipeline using [KMC3](https://github.com/refresh-bio/KMC) 164 | 165 | Make sure to have `kmc` installed. One recommended way is to create a conda environment and [install it there](https://anaconda.org/bioconda/kmc) 166 | 167 | ```bash 168 | kmer_size=6 169 | input="path/to/sequence.fa" 170 | output="path/to/count-kmers.txt" 171 | 172 | mkdir -p tmp-kmc 173 | kmc -v -k$kmer_size -m4 -sm -ci0 -cs100000 -b -t4 -fa $input $input "tmp-kmc" 174 | kmc_tools -t4 -v transform $input dump $output 175 | rm -r $input.kmc_pre $input.kmc_suf 176 | ``` 177 | the output file `path/to/count-kmers.txt` can be used with `FCGRKmc` 178 | 179 | ```python 180 | from complexcgr import FCGRKmc 181 | 182 | kmer = 6 183 | fcgr = FCGRKmc(kmer) 184 | 185 | arr = fcgr("path/to/count-kmers.txt") # k-mer counts ordered in a matrix of 2^k x 2^k 186 | 187 | 188 | # to visualize the distribution of k-mers. 189 | # Frequencies are scaled between [min, max] values. 190 | # White color corresponds to the minimum value of frequency 191 | # Black color corresponds to the maximum value of frequency 192 | fcgr.plot(arr) 193 | 194 | # Save it with numpy 195 | import numpy as np 196 | np.save("path_save/fcgr.npy",arr) 197 | ``` 198 | 199 | ___ 200 | # Videos 201 | 202 | **CGR encoding** 203 | 204 | [![CGR encoding of a sequence](https://img.youtube.com/vi/HU15ge0fkOY/0.jpg)](https://youtu.be/HU15ge0fkOY) 205 | 206 | **CGR encoding of all k-mers** 207 | 208 | [![How are k-mers distributed for different k](https://img.youtube.com/vi/oYLT11Q9n5M/0.jpg)](https://youtu.be/oYLT11Q9n5M) 209 | 210 | **ComplexCGR encoding** 211 | 212 | [![How are k-mers ordered based on lexicographic order for k=2](https://img.youtube.com/vi/xKyXplS5KFk/0.jpg)](https://youtu.be/xKyXplS5KFk) 213 | 214 | **ComplexCGR and Symmetry** 215 | 216 | [![Conjugate of a complex number has a meaning (reverse sequence)](https://img.youtube.com/vi/YmcxVId4_4w/0.jpg)](https://www.youtube.com/YmcxVId4_4w) 217 | 218 | 219 | # Functionalities/TODO list 220 | ___ 221 | > version 0.8.0: 222 | A list of available classes and functionalities are listed below: 223 | 224 | 225 | **Encoders** 226 | The encoders are functions that map a sequence $s \in \{A,C,G,T\}$ to a point in the plane. 227 | `CGR`, `iCGR`, and `ComplexCGR`. 228 | 229 | `CGR` Chaos Game Representation: encodes a DNA sequence in 3 numbers $(N,x,y)$ 230 | - [x] encode a sequence. 231 | - [x] recover a sequence from a CGR encoding. 232 | 233 | `iCGR` integer CGR: encodes a DNA sequence in 3 integers $(N,x,y)$. 234 | 235 | `CGR` Chaos Game Representation: encodes a DNA sequence in 3 numbers $(N,x,y)$ 236 | - [x] encode a sequence. 237 | - [x] recover a sequence from a CGR encoding. 238 | 239 | `iCGR` integer CGR: encodes a DNA sequence in 3 integers $(N,x,y)$. 240 | - [x] encode a sequence 241 | - [x] recover a sequence from an iCGR encoding 242 | 243 | `ComplexCGR`: encodes a DNA sequence in 2 integers $(k,N)$. 244 | - [x] encode a sequence 245 | - [x] recover a sequence from a ComplexCGR encoding 246 | - [x] plot sequence of ComplexCGR encodings 247 | 248 | **Image for distribution of k-mers** 249 | 250 | - [x] `FCGR` Frequency Matrix CGR: representation as an image for k-mer representativity, based on CGR. 251 | - [x] generates FCGR from an arbitrary n-long sequence. 252 | - [x] plot FCGR. 253 | - [x] save FCGR generated. 254 | - [x] save FCGR in different bits. 255 | - [x] `FCGRKmc` Same as `FCGR` but receives as input the file with k-mer counts generated with [KMC](https://github.com/refresh-bio/KMC) 256 | - [x] `ComplexFCGR`: Frequency ComplexCGR: representation as an image (circle) for k-mer representativity, based on ComplexCGR. 257 | - [x] generates ComplexFCGR from an arbitrary n-long sequence. 258 | - [x] plot ComplexFCGR. 259 | - [x] save ComplexFCGR generated. 260 | 261 | - [ ] `PercentileFCGR`: 262 | - [A universal DNA signature for the Tree of Life. EcoEvoRxiv](https://doi.org/10.32942/X24891) 263 | - [ ] `SpacedFCGR`: Create FCGR from spaced-mers 264 | - [Spaced seeds improve k-mer-based metagenomic classification, Bioninformatics](https://academic.oup.com/bioinformatics/article/31/22/3584/240663) 265 | - [Effects of spaced k-mers on alignment-free genotyping](https://academic.oup.com/bioinformatics/article/39/Supplement_1/i213/7210439) 266 | 267 | # Author 268 | 269 | `complexcgr` is developed by [Jorge Avila Cartes](https://github.com/jorgeavilacartes/) 270 | 271 | 272 | # Related publications 273 | 274 | - [Accurate and fast clade assignment via deep learning and frequency chaos game representation](https://doi.org/10.1093/gigascience/giac119) 275 | - [PanSpace: Fast and Scalable Indexing for Massive Bacterial Databases](https://doi.org/10.1101/2025.03.19.644115) -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | # complexCGR 2 | 3 | A complex representation for DNA, that preserves some properties of the CGR from the 'Chaos Game Representation for gene structure' by Jeffrey in 1990. 4 | 5 | Each nucleotide will be assigned to one quadrant (I,II,III and IV). This distribution will be the same for the CGR and complexCGR implementations (I:A,II:C,III:G,IV:T) -------------------------------------------------------------------------------- /complexCGR.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlgoLab/complexCGR/930a3804af8d43f81db3a383390ad56d5afaa72d/complexCGR.pdf -------------------------------------------------------------------------------- /complexcgr/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ ="0.8.0" 2 | 3 | # encodings 4 | from .cgr import CGR 5 | from .icgr import iCGR 6 | from .complexcgr import ComplexCGR 7 | 8 | # from k-mers 9 | from .fcgr import FCGR 10 | from .fcgr_kmc import FCGRKmc 11 | from .complexfcgr import ComplexFCGR -------------------------------------------------------------------------------- /complexcgr/cgr.py: -------------------------------------------------------------------------------- 1 | "From original work: CGR for gene structure" 2 | from typing import Dict, Optional 3 | from collections import namedtuple 4 | 5 | # coordinates for x+iy 6 | Coord = namedtuple("Coord", ["x","y"]) 7 | 8 | # coordinates for a CGR encoding 9 | CGRCoords = namedtuple("CGRCoords", ["N","x","y"]) 10 | 11 | # coordinates for each nucleotide in the 2d-plane 12 | DEFAULT_COORDS = dict(A=Coord(1,1),C=Coord(-1,1),G=Coord(-1,-1),T=Coord(1,-1)) 13 | 14 | class CGR: 15 | "Chaos Game Representation for DNA" 16 | def __init__(self, coords: Optional[Dict[chr,tuple]]=None): 17 | self.nucleotide_coords = DEFAULT_COORDS if coords is None else coords 18 | self.cgr_coords = CGRCoords(0,0,0) 19 | 20 | def nucleotide_by_coords(self,x,y): 21 | "Get nucleotide by coordinates (x,y)" 22 | # filter nucleotide by coordinates 23 | filtered = dict(filter(lambda item: item[1] == Coord(x,y), self.nucleotide_coords.items())) 24 | 25 | return list(filtered.keys())[0] 26 | 27 | def forward(self, nucleotide: str): 28 | "Compute next CGR coordinates" 29 | x = (self.cgr_coords.x + self.nucleotide_coords.get(nucleotide).x)/2 30 | y = (self.cgr_coords.y + self.nucleotide_coords.get(nucleotide).y)/2 31 | 32 | # update cgr_coords 33 | self.cgr_coords = CGRCoords(self.cgr_coords.N+1,x,y) 34 | 35 | def backward(self,): 36 | "Compute last CGR coordinates. Current nucleotide can be inferred from (x,y)" 37 | # get current nucleotide based on coordinates 38 | n_x,n_y = self.coords_current_nucleotide() 39 | nucleotide = self.nucleotide_by_coords(n_x,n_y) 40 | 41 | # update coordinates to the previous one 42 | x = 2*self.cgr_coords.x - n_x 43 | y = 2*self.cgr_coords.y - n_y 44 | 45 | # update cgr_coords 46 | self.cgr_coords = CGRCoords(self.cgr_coords.N-1,x,y) 47 | 48 | return nucleotide 49 | 50 | def coords_current_nucleotide(self,): 51 | x = 1 if self.cgr_coords.x>0 else -1 52 | y = 1 if self.cgr_coords.y>0 else -1 53 | return x,y 54 | 55 | def encode(self, sequence: str): 56 | "From DNA sequence to CGR" 57 | # reset starting position to (0,0,0) 58 | self.reset_coords() 59 | for nucleotide in sequence: 60 | self.forward(nucleotide) 61 | return self.cgr_coords 62 | 63 | def reset_coords(self,): 64 | self.cgr_coords = CGRCoords(0,0,0) 65 | 66 | def decode(self, N:int, x:int, y:int)->str: 67 | "From CGR to DNA sequence" 68 | self.cgr_coords = CGRCoords(N,x,y) 69 | 70 | # decoded sequence 71 | sequence = [] 72 | 73 | # Recover the entire genome 74 | while self.cgr_coords.N>0: 75 | nucleotide = self.backward() 76 | sequence.append(nucleotide) 77 | return "".join(sequence[::-1]) -------------------------------------------------------------------------------- /complexcgr/complexcgr.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, List 2 | from collections import namedtuple 3 | 4 | # coordinates for x+iy 5 | Coord = namedtuple("Coord", ["x","y"]) 6 | 7 | # coordinates for a CGR encoding 8 | CGRCoords = namedtuple("CGRCoord", ["k","N"]) 9 | 10 | class ComplexCGR: 11 | "Complex Chaos Game Representation of DNA" 12 | def __init__(self, nucleotide_order: List[str] = ["A","C","G","T"]): 13 | self.nucleotide_order = nucleotide_order 14 | self.cgr_coords = CGRCoords(0,0) # complexCGR coordinates 15 | 16 | def id(self, nucleotide): 17 | return self.nucleotide_order.index(nucleotide) 18 | 19 | def forward(self, nucleotide: str): 20 | "compute next complexCGR coordinates" 21 | k = self.id(nucleotide)*4**(self.cgr_coords.N) + self.cgr_coords.k 22 | 23 | # update cgr_coords 24 | self.cgr_coords = CGRCoords(k,self.cgr_coords.N+1) 25 | 26 | def backward(self,): 27 | "compute last complexCGR coordinates" 28 | nucleotide = self.current_nucleotide() 29 | 30 | # compute previous k 31 | k = self.cgr_coords.k - self.id(nucleotide)*4**(self.cgr_coords.N-1) 32 | 33 | # update cgr_coords 34 | self.cgr_coords = CGRCoords(k,self.cgr_coords.N-1) 35 | 36 | return nucleotide 37 | 38 | def encode(self, sequence: str): 39 | "From DNA to complexCGR" 40 | self.reset_coords() 41 | for nucleotide in sequence: 42 | self.forward(nucleotide) 43 | return self.cgr_coords 44 | 45 | def decode(self, k: int, N: int): 46 | "From complexCGR to DNA" 47 | self.cgr_coords = CGRCoords(k,N) 48 | 49 | # decoded sequence 50 | sequence = [] 51 | 52 | # Recover the entire genome 53 | while self.cgr_coords.N>0: 54 | nucleotide = self.backward() 55 | sequence.append(nucleotide) 56 | return "".join(sequence[::-1]) 57 | 58 | def current_nucleotide(self,): 59 | "Get current nucleotide based on k and N" 60 | k,N = self.cgr_coords.k, self.cgr_coords.N 61 | alpha = k/4**N 62 | if alpha <0.25: 63 | return self.nucleotide_order[0] 64 | elif alpha <0.5: 65 | return self.nucleotide_order[1] 66 | elif alpha < 0.75: 67 | return self.nucleotide_order[2] 68 | else: 69 | return self.nucleotide_order[3] 70 | 71 | def reset_coords(self,): 72 | self.cgr_coords = CGRCoords(0,0) 73 | -------------------------------------------------------------------------------- /complexcgr/complexfcgr.py: -------------------------------------------------------------------------------- 1 | from . import ComplexCGR 2 | import matplotlib.pyplot as plt 3 | from itertools import product 4 | from collections import defaultdict 5 | from tqdm import tqdm 6 | from PIL import Image 7 | import numpy as np 8 | 9 | 10 | class ComplexFCGR(ComplexCGR): 11 | """Circular density plot based on CGR""" 12 | 13 | def __init__(self, k: int): 14 | super().__init__() 15 | self.k = k # k-mer representation 16 | self.kmers = product("ACGT", repeat=self.k) # all kmers of length k 17 | self.freq_kmer = None # dict to save representativity of each kmer 18 | self.probabilities = None # dict to save probabilities/density for each kmer 19 | self.fig = None # to save matlotlib figure and then save as image 20 | 21 | def __call__(self, sequence: str, w=1): 22 | self.count_kmers(sequence) 23 | self.kmer_probabilities(sequence) 24 | self.plot(w) 25 | 26 | def count_kmers(self, sequence: str): 27 | self.freq_kmer = defaultdict(int) 28 | # representativity of kmers 29 | len_seq = len(sequence) 30 | for j,_ in enumerate(sequence): 31 | if j+self.k <= len_seq: 32 | subseq = sequence[j:j+self.k] 33 | if "N" not in subseq: 34 | self.freq_kmer[subseq] +=1 35 | 36 | def kmer_probabilities(self, sequence: str): 37 | self.probabilities = defaultdict(float) 38 | N=len(sequence) 39 | for key, value in self.freq_kmer.items(): 40 | self.probabilities[key] = float(value) / (N - self.k + 1) 41 | 42 | def plot(self, w: int = 1): 43 | "Given a FCGR, plot it in grayscale" 44 | ax = plt.subplot(111, polar=True) 45 | center, bottom, width, height = self.compute_input_plot() 46 | 47 | # scale width by 'w' 48 | width = [w*_ for _ in width] 49 | print("generating plot") 50 | ax.bar(x=center, # center of the angle 51 | width=width, # width of the angle 52 | bottom=bottom, # lowest value 53 | height=height, # highest value 54 | ) 55 | 56 | ax.axes.get_xaxis().set_visible(False) 57 | ax.axes.get_yaxis().set_visible(False) 58 | 59 | return ax.figure 60 | 61 | def save(self, ccgr, path: str): 62 | "save complexFCGR as image" 63 | # get figure 64 | fig = self.plot() 65 | 66 | # transform figure to Image 67 | img = self.fig2img(fig) 68 | 69 | # save image 70 | img.save(path) 71 | plt.close(fig) 72 | 73 | @staticmethod 74 | def fig2img(fig): 75 | "Convert a Matplotlib figure to a PIL Image and return it" 76 | #https://stackoverflow.com/questions/57316491/how-to-convert-matplotlib-figure-to-pil-image-object-without-saving-image 77 | import io 78 | buf = io.BytesIO() 79 | fig.savefig(buf) 80 | buf.seek(0) 81 | img = Image.open(buf) 82 | return img 83 | 84 | 85 | def compute_input_plot(self,): 86 | "Compute input for plot CFCGR" 87 | delta = 2*np.pi/4**self.k # angle between consecutive roots 88 | 89 | center = [] 90 | width = [] 91 | height = [] 92 | bottom = [] 93 | 94 | for kmer in tqdm(self.probabilities): 95 | h = self.probabilities.get(kmer,0.0) # height (density) of the bar in the circle 96 | theta = 2*self.encode(kmer).k*np.pi/4**self.k # angle of k-esim root 97 | c = theta + delta/2 # center of the angle 98 | center.append(c) 99 | bottom.append(0) 100 | width.append(50*delta) 101 | height.append(h) 102 | 103 | return center, bottom, width, height -------------------------------------------------------------------------------- /complexcgr/fcgr.py: -------------------------------------------------------------------------------- 1 | from . import CGR 2 | from PIL import Image 3 | from itertools import product 4 | from collections import defaultdict 5 | import numpy as np 6 | 7 | NUC_COMPLEMENT = {n:c for n,c in zip ("ACGT","TGCA")} 8 | 9 | class FCGR(CGR): 10 | """Frequency matrix CGR 11 | an (2**k x 2**k) 2D representation will be created for a 12 | n-long sequence. 13 | - k represents the k-mer. 14 | - 2**k x 2**k = 4**k the total number of k-mers (sequences of length k) 15 | """ 16 | 17 | def __init__(self, k: int, use_canonical_kmers: bool = False ,bits: int = 8): 18 | super().__init__() 19 | self.k = k # k-mer representation 20 | self.use_canonical_kmers = use_canonical_kmers 21 | self.kmers = list("".join(kmer) for kmer in product("ACGT", repeat=self.k)) 22 | 23 | if use_canonical_kmers is True: 24 | self.kmer2pixel = self._kmer2pixel_canonical_kmers() 25 | else: 26 | self.kmer2pixel = self.kmer2pixel_position() 27 | 28 | self.bits = bits 29 | self.max_color = 2**bits-1 30 | 31 | def __call__(self, sequence: str): 32 | "Given a DNA sequence, returns an array with his FCGR" 33 | self.count_kmers(sequence) 34 | 35 | # Create an empty array to save the FCGR values 36 | array_size = int(2**self.k) 37 | fcgr = np.zeros((array_size,array_size)) 38 | 39 | # Assign frequency to each box in the matrix 40 | for kmer, freq in self.freq_kmer.items(): 41 | pos_x, pos_y = self.kmer2pixel[kmer] 42 | fcgr[int(pos_x)-1,int(pos_y)-1] = freq 43 | return fcgr 44 | 45 | def count_kmer(self, kmer): 46 | if "N" not in kmer: 47 | self.freq_kmer[kmer] += 1 48 | 49 | def count_kmers(self, sequence: str): 50 | self.freq_kmer = defaultdict(int) 51 | # representativity of kmers 52 | last_j = len(sequence) - self.k + 1 53 | kmers = (sequence[i:(i+self.k)] for i in range(last_j)) 54 | # count kmers in a dictionary 55 | list(self.count_kmer(kmer) for kmer in kmers) 56 | 57 | def pixel_position(self, kmer: str): 58 | "Get pixel position in the FCGR matrix for a k-mer" 59 | 60 | coords = self.encode(kmer) 61 | N,x,y = coords.N, coords.x, coords.y 62 | 63 | # Coordinates from [-1,1]² to [1,2**k]² 64 | np_coords = np.array([(x + 1)/2, (y + 1)/2]) # move coordinates from [-1,1]² to [0,1]² 65 | np_coords *= 2**self.k # rescale coordinates from [0,1]² to [0,2**k]² 66 | x,y = np.ceil(np_coords) # round to upper integer 67 | 68 | # Turn coordinates (cx,cy) into pixel (px,py) position 69 | # px = 2**k-cy+1, py = cx 70 | return 2**self.k-int(y)+1, int(x) 71 | 72 | def kmer2pixel_position(self,): 73 | kmer2pixel = dict() 74 | for kmer in self.kmers: 75 | kmer2pixel[kmer] = self.pixel_position(kmer) 76 | return kmer2pixel 77 | 78 | def plot(self, fcgr): 79 | "Given a FCGR, plot it in grayscale" 80 | img_pil = self.array2img(fcgr) 81 | return img_pil 82 | 83 | def save_img(self, fcgr, path: str): 84 | "Save image in grayscale for the FCGR provided as input" 85 | img_pil = self.array2img(fcgr) 86 | img_pil.save(path) 87 | 88 | def array2img(self, array): 89 | "Array to PIL image" 90 | m, M = array.min(), array.max() 91 | # rescale to [0,1] 92 | img_rescaled = (array - m) / (M-m) 93 | 94 | # invert colors black->white 95 | img_array = np.ceil(self.max_color - img_rescaled*self.max_color) 96 | dtype = eval(f"np.int{self.bits}") 97 | img_array = np.array(img_array, dtype=dtype) 98 | 99 | # convert to Image 100 | img_pil = Image.fromarray(img_array,'L') 101 | return img_pil 102 | 103 | # # --------------- canonical k-mers ---------------- # # 104 | @staticmethod 105 | def reverse_complement(kmer: str): 106 | rev_kmer = list(kmer)[::-1] 107 | return "".join([NUC_COMPLEMENT[n] for n in rev_kmer]) 108 | 109 | def get_canonical_kmer(self, kmer: str): 110 | rev_complement = self.reverse_complement(kmer) 111 | return kmer if kmer < rev_complement else rev_complement 112 | 113 | def _kmer2pixel_canonical_kmers(self,): 114 | # change pixel position of non-canonical kmers 115 | kmer2pixel = dict() 116 | for kmer in self.kmers: 117 | canonical_kmer = self.get_canonical_kmer(kmer) 118 | if kmer != canonical_kmer: 119 | kmer2pixel[kmer] = kmer2pixel[canonical_kmer] 120 | return kmer2pixel -------------------------------------------------------------------------------- /complexcgr/fcgr_kmc.py: -------------------------------------------------------------------------------- 1 | from . import FCGR 2 | 3 | import gzip 4 | import numpy as np 5 | 6 | class FCGRKmc(FCGR): 7 | """ 8 | Create FCGR with the option of using canonical kmers from KMC output 9 | """ 10 | def __init__(self, k: int, use_canonical_kmers: bool=False): 11 | super().__init__(k, use_canonical_kmers) 12 | self.k = k # k-mer representation 13 | self.use_canonical_kmers = use_canonical_kmers 14 | 15 | def __call__(self, path_kmc_output): 16 | "Given a path to a kmc output file, return the FCGR using canonical kmers as an array" 17 | # Create an empty array to save the FCGR values 18 | array_size = int(2**self.k) 19 | fcgr = np.zeros((array_size,array_size)) 20 | 21 | if str(path_kmc_output).endswith(".txt"): 22 | with open(path_kmc_output) as fp: 23 | for line in fp: 24 | kmer, freq = line.split("\t") 25 | pos_x, pos_y = self.kmer2pixel[kmer] 26 | fcgr[int(pos_x)-1,int(pos_y)-1] += int(freq) 27 | else: 28 | with gzip.open(path_kmc_output,'rt') as f: 29 | for line in f: 30 | line = line.strip() 31 | kmer, freq = line.split() 32 | pos_x, pos_y = self.kmer2pixel[kmer] 33 | fcgr[int(pos_x)-1,int(pos_y)-1] += int(freq) 34 | 35 | return fcgr -------------------------------------------------------------------------------- /complexcgr/fcgr_samples.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from Bio import SeqIO 3 | from collections import defaultdict 4 | from pathlib import Path 5 | from tqdm import tqdm 6 | from typing import List, Union 7 | from complexcgr import FCGR 8 | 9 | # input for FCGR Samples 10 | _path_fastq = Union[str, Path] # path can be a string or a Path instance 11 | _fastq = Union[_path_fastq,List[_path_fastq]] # either a single path or a list of paths to fastq files 12 | 13 | class FCGRSamples(FCGR): 14 | 15 | def __init__(self, k: int, bits: int = 8): 16 | super().__init__(k, bits) 17 | 18 | def __call__(self, path_fastq: _fastq, consider_quality: bool = False): 19 | "Given a (list) of fastq files, return the FCGR matrix" 20 | 21 | ## ---- New for reads ---- 22 | 23 | # for each call, we start to count the frequencies 24 | self.freq_kmer = defaultdict(int) 25 | if consider_quality is True: 26 | self.qual_kmer = defaultdict(int) 27 | 28 | # transform to list to iterate 29 | path_fastq = path_fastq if type(path_fastq) is list else [path_fastq] 30 | 31 | # For each file, count kmers on their reads 32 | for path in path_fastq: 33 | fastq = self.load_fastq(path) 34 | n_reads = self.count_reads(path) 35 | 36 | # count kmers in each read 37 | for sample in tqdm(fastq,total=n_reads,desc=f"Counting kmers on {str(Path(path).stem)}"): 38 | read = sample.seq 39 | if consider_quality is True: 40 | qual = sample.letter_annotations["phred_quality"] 41 | self.count_kmers_qualities(str(read),qual) 42 | else: 43 | self.count_kmers(str(read)) 44 | 45 | ## ---- End new for reads ---- 46 | 47 | # Create an empty array to save the FCGR values 48 | if consider_quality is False: 49 | array_size = int(2**self.k) 50 | fcgr = np.zeros((array_size,array_size)) 51 | else: 52 | array_size = int(2**self.k) 53 | fcgr = np.zeros((array_size,array_size,2)) 54 | 55 | # Assign frequency to each box in the matrix 56 | for kmer, freq in self.freq_kmer.items(): 57 | pos_x, pos_y = self.kmer2pixel[kmer] 58 | 59 | if consider_quality is True: 60 | fcgr[int(pos_x)-1,int(pos_y)-1,0] = freq 61 | fcgr[int(pos_x)-1,int(pos_y)-1,1] = self.qual_kmer[kmer] 62 | else: 63 | fcgr[int(pos_x)-1,int(pos_y)-1] = freq 64 | 65 | return fcgr if consider_quality is False else self.rescale_fcgr_qualities(fcgr) 66 | 67 | 68 | def load_fastq(self, path): 69 | "Load a fastq file" 70 | fastq = SeqIO.parse(str(path), "fastq") 71 | return fastq 72 | 73 | def count_kmers(self, read: str): 74 | # representativity of kmers 75 | last_j = len(read) - self.k + 1 76 | kmers = (read[i:(i+self.k)] for i in range(last_j)) 77 | # count kmers in a dictionary 78 | list(self.count_kmer(kmer) for kmer in kmers) 79 | 80 | @staticmethod 81 | def count_reads(path): 82 | "Count reads in a file to define progress bar" 83 | n_reads = 0 84 | with open(str(path)) as fp: 85 | for line in fp: 86 | if line.startswith("@"): 87 | n_reads += 1 88 | return n_reads 89 | 90 | def count_kmer(self, kmer): 91 | if "N" not in kmer: 92 | self.freq_kmer[kmer] += 1 93 | 94 | 95 | def count_kmer_quality(self, kmer, qmer): 96 | """Count kmers and qualities 97 | For quality of a kmer, the mean of qualities for each nucleotide in the kmer will be saved""" 98 | if "N" not in kmer: 99 | self.freq_kmer[kmer] += 1 100 | self.qual_kmer[kmer] += qmer.mean() 101 | 102 | def count_kmers_qualities(self,read,qual): 103 | "Count kmers and qualities" 104 | 105 | # representativity of kmers 106 | last_j = len(read) - self.k + 1 107 | kmers = (read[i:(i+self.k)] for i in range(last_j)) 108 | qmers = (np.array(qual[i:(i+self.k)]) for i in range(last_j)) # qualities for each kmer 109 | 110 | # count kmers and qualities in a dictionary 111 | list(self.count_kmer_quality(kmer,qmer) for (kmer,qmer) in zip(kmers,qmers)) 112 | 113 | @staticmethod 114 | def rescale_fcgr_qualities(fcgr): 115 | "Divide each cumulate quality by the freq of its kmer" 116 | freqs, quals = fcgr[:,:,0], fcgr[:,:,1] 117 | fcgr[:,:,1] = np.divide(quals, freqs, out = np.zeros_like(quals), where = quals!=0) 118 | return fcgr -------------------------------------------------------------------------------- /complexcgr/icgr.py: -------------------------------------------------------------------------------- 1 | "From original work: CGR for gene structure" 2 | from itertools import product 3 | from tqdm import tqdm 4 | from typing import Dict, Optional 5 | from collections import defaultdict, namedtuple 6 | import numpy as np 7 | 8 | # coordinates for x+iy 9 | Coord = namedtuple("Coord", ["x","y"]) 10 | 11 | # coordinates for a CGR encoding 12 | CGRCoords = namedtuple("CGRCoords", ["N","x","y"]) 13 | 14 | # coordinates for each nucleotide in the 2d-plane 15 | DEFAULT_COORDS = dict(A=Coord(1,1),C=Coord(-1,1),G=Coord(-1,-1),T=Coord(1,-1)) 16 | 17 | class iCGR: 18 | "integer Chaos Game Representation for DNA" 19 | def __init__(self, coords: Optional[Dict[chr,tuple]]=None): 20 | self.nucleotide_coords = DEFAULT_COORDS if coords is None else coords 21 | self.cgr_coords = CGRCoords(0,0,0) 22 | 23 | def nucleotide_by_coords(self,x,y): 24 | "Get nucleotide by coordinates (x,y)" 25 | # filter nucleotide by coordinates 26 | filtered = dict(filter(lambda item: item[1] == Coord(x,y), self.nucleotide_coords.items())) 27 | 28 | return list(filtered.keys())[0] 29 | 30 | def forward(self, nucleotide: str): 31 | "Compute next CGR coordinates" 32 | # current length 33 | N = self.cgr_coords.N 34 | 35 | # compute next coordinates 36 | x = self.cgr_coords.x + self.nucleotide_coords.get(nucleotide).x * 2**N 37 | y = self.cgr_coords.y + self.nucleotide_coords.get(nucleotide).y * 2**N 38 | 39 | # update cgr_coords: iCGR starts in the corner of the first nucleotide 40 | 41 | if N>0: 42 | self.cgr_coords = CGRCoords(self.cgr_coords.N+1,x,y,) 43 | else: 44 | self.cgr_coords = CGRCoords(1, 45 | self.nucleotide_coords.get(nucleotide).x, 46 | self.nucleotide_coords.get(nucleotide).y, 47 | ) 48 | 49 | def backward(self,): 50 | "Compute last CGR coordinates. Current nucleotide can be inferred from (x,y)" 51 | # get current nucleotide based on coordinates 52 | n_x,n_y = self.coords_current_nucleotide() 53 | nucleotide = self.nucleotide_by_coords(n_x,n_y) 54 | 55 | # current length 56 | N = self.cgr_coords.N 57 | 58 | # update coordinates to the previous one 59 | x = self.cgr_coords.x - self.nucleotide_coords.get(nucleotide).x * 2**(N-1) 60 | y = self.cgr_coords.y - self.nucleotide_coords.get(nucleotide).y * 2**(N-1) 61 | 62 | # update cgr_coords 63 | self.cgr_coords = CGRCoords(self.cgr_coords.N-1,x,y) 64 | 65 | return nucleotide 66 | 67 | def coords_current_nucleotide(self,): 68 | x = 1 if self.cgr_coords.x>0 else -1 69 | y = 1 if self.cgr_coords.y>0 else -1 70 | return x,y 71 | 72 | def encode(self, sequence: str): 73 | "From DNA sequence to CGR" 74 | # reset starting position to (0,0,0) 75 | self.reset_coords() 76 | for nucleotide in sequence: 77 | self.forward(nucleotide) 78 | return self.cgr_coords 79 | 80 | def reset_coords(self,): 81 | self.cgr_coords = CGRCoords(0,0,0) 82 | 83 | def decode(self, N:int, x:int, y:int)->str: 84 | "From CGR to DNA sequence" 85 | self.cgr_coords = CGRCoords(N,x,y) 86 | 87 | # decoded sequence 88 | sequence = [] 89 | 90 | # Recover the entire genome 91 | while self.cgr_coords.N>0: 92 | nucleotide = self.backward() 93 | sequence.append(nucleotide) 94 | return "".join(sequence[::-1]) -------------------------------------------------------------------------------- /img/ACG-complexCGR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlgoLab/complexCGR/930a3804af8d43f81db3a383390ad56d5afaa72d/img/ACG-complexCGR.png -------------------------------------------------------------------------------- /img/ACG.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlgoLab/complexCGR/930a3804af8d43f81db3a383390ad56d5afaa72d/img/ACG.jpg -------------------------------------------------------------------------------- /img/ACG_16bits.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlgoLab/complexCGR/930a3804af8d43f81db3a383390ad56d5afaa72d/img/ACG_16bits.jpg -------------------------------------------------------------------------------- /img/CGA.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlgoLab/complexCGR/930a3804af8d43f81db3a383390ad56d5afaa72d/img/CGA.jpg -------------------------------------------------------------------------------- /img/CGAN.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlgoLab/complexCGR/930a3804af8d43f81db3a383390ad56d5afaa72d/img/CGAN.jpg -------------------------------------------------------------------------------- /img/SAMD00003784.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlgoLab/complexCGR/930a3804af8d43f81db3a383390ad56d5afaa72d/img/SAMD00003784.jpeg -------------------------------------------------------------------------------- /img/SAMD00032020.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlgoLab/complexCGR/930a3804af8d43f81db3a383390ad56d5afaa72d/img/SAMD00032020.jpeg -------------------------------------------------------------------------------- /img/SAMD00111209.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlgoLab/complexCGR/930a3804af8d43f81db3a383390ad56d5afaa72d/img/SAMD00111209.jpeg -------------------------------------------------------------------------------- /img/SAMD00111306.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlgoLab/complexCGR/930a3804af8d43f81db3a383390ad56d5afaa72d/img/SAMD00111306.jpeg -------------------------------------------------------------------------------- /img/complexcgr-readme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlgoLab/complexCGR/930a3804af8d43f81db3a383390ad56d5afaa72d/img/complexcgr-readme.png -------------------------------------------------------------------------------- /img/logo-complexCGR-nb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlgoLab/complexCGR/930a3804af8d43f81db3a383390ad56d5afaa72d/img/logo-complexCGR-nb.png -------------------------------------------------------------------------------- /img/logo-complexCGR-v2-nb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlgoLab/complexCGR/930a3804af8d43f81db3a383390ad56d5afaa72d/img/logo-complexCGR-v2-nb.png -------------------------------------------------------------------------------- /img/logo-complexCGR-v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlgoLab/complexCGR/930a3804af8d43f81db3a383390ad56d5afaa72d/img/logo-complexCGR-v2.png -------------------------------------------------------------------------------- /img/logo-complexCGR-v3-nb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlgoLab/complexCGR/930a3804af8d43f81db3a383390ad56d5afaa72d/img/logo-complexCGR-v3-nb.png -------------------------------------------------------------------------------- /img/logo-complexCGR-v3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlgoLab/complexCGR/930a3804af8d43f81db3a383390ad56d5afaa72d/img/logo-complexCGR-v3.png -------------------------------------------------------------------------------- /img/logo-complexCGR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlgoLab/complexCGR/930a3804af8d43f81db3a383390ad56d5afaa72d/img/logo-complexCGR.png -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "atomicwrites" 5 | version = "1.4.1" 6 | description = "Atomic file writes." 7 | optional = false 8 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 9 | files = [ 10 | {file = "atomicwrites-1.4.1.tar.gz", hash = "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11"}, 11 | ] 12 | 13 | [[package]] 14 | name = "attrs" 15 | version = "23.2.0" 16 | description = "Classes Without Boilerplate" 17 | optional = false 18 | python-versions = ">=3.7" 19 | files = [ 20 | {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, 21 | {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, 22 | ] 23 | 24 | [package.extras] 25 | cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] 26 | dev = ["attrs[tests]", "pre-commit"] 27 | docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] 28 | tests = ["attrs[tests-no-zope]", "zope-interface"] 29 | tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] 30 | tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] 31 | 32 | [[package]] 33 | name = "biopython" 34 | version = "1.82" 35 | description = "Freely available tools for computational molecular biology." 36 | optional = false 37 | python-versions = ">=3.8" 38 | files = [ 39 | {file = "biopython-1.82-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:713be5e1e8571ea151864544dfcd2637eaf98c67a6e47b69781d325feb02f6b9"}, 40 | {file = "biopython-1.82-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5bc908e84278bf61ac901a0c1b695c85ce49491957e0ab07e1e2afc216882525"}, 41 | {file = "biopython-1.82-cp310-cp310-win32.whl", hash = "sha256:f53aff30f01ac9a8aa1fd42dab347a96ee5312945098dfa38f9a5125f6e913fd"}, 42 | {file = "biopython-1.82-cp310-cp310-win_amd64.whl", hash = "sha256:0f3f685a2d85348b8c84c6eebe58a74cef7e1158ac52ae5aa91789436907f0e1"}, 43 | {file = "biopython-1.82-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c9bc080b7dc6cd6acbf2576766136e8e54acbcc6b7a29ad8075cb5a73f4cfb97"}, 44 | {file = "biopython-1.82-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7802b5033edaf34bd2fbd96b87f96999a6808caa0064c91087c7f1340624898"}, 45 | {file = "biopython-1.82-cp311-cp311-win32.whl", hash = "sha256:ec35893b32458f6fa0c98d5f02d801a5fe76961ac66473455f51c0575562c594"}, 46 | {file = "biopython-1.82-cp311-cp311-win_amd64.whl", hash = "sha256:40297d418bb142a7ea1a47faedc24bbe21b0ba455f3805373264470e5cb6ec5c"}, 47 | {file = "biopython-1.82-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:96f77bd6540683c8958e4ebf55b58e8caa26d20db72891915d06670b783e9cdb"}, 48 | {file = "biopython-1.82-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49b829c2276a0711106663af632c7e203695a5cf082d488d6e10b8aca5ec63e4"}, 49 | {file = "biopython-1.82-cp312-cp312-win32.whl", hash = "sha256:54a9b200d4960ed2a4ec85faac2124ffa278afa58d22e07e2d15ca7509219ea1"}, 50 | {file = "biopython-1.82-cp312-cp312-win_amd64.whl", hash = "sha256:762547037038d42c9ac98877fc32d4aeba798077129df7790cb178256171a4e5"}, 51 | {file = "biopython-1.82-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cb013256742d31e24fd5093d55511f58bc6a93b8ac723d2ca3b33c7904f1ca14"}, 52 | {file = "biopython-1.82-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16829760fab60ba17141b7a81494fed837c6f29ea28cdcfb3070764c8e8f2ff1"}, 53 | {file = "biopython-1.82-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c6af82894dd4f736d737fdea62008a19966251ba39aef39a0ce8b41321305ad5"}, 54 | {file = "biopython-1.82-cp38-cp38-win32.whl", hash = "sha256:a1ff583b2f8b314a4c2d612aad4f4b73827a5f741b391f3a834b0c192a4f1527"}, 55 | {file = "biopython-1.82-cp38-cp38-win_amd64.whl", hash = "sha256:0198f23776d9cb9d514a797e81a024f486adac973b252a2f4696995a5a163745"}, 56 | {file = "biopython-1.82-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c88e9f87d1b07958e7e1e25ff20efced4796daf650e5290692b5c3ff9aebf9d3"}, 57 | {file = "biopython-1.82-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e2533db9275c3e1438151260844e7683f91308da320df02a4c28fb7053ea3a9"}, 58 | {file = "biopython-1.82-cp39-cp39-win32.whl", hash = "sha256:80f48d220b92e747300281602f52e98ec6c537ddd4921b580d9a0368bae05ff5"}, 59 | {file = "biopython-1.82-cp39-cp39-win_amd64.whl", hash = "sha256:73d619611bd7cf9d2ad8b3217b08d3796acfabb765b0771ad2ff7ee2e46a59b0"}, 60 | {file = "biopython-1.82.tar.gz", hash = "sha256:a9b10d959ae88a9744a91c6ce3601f4c86e7ec41679bc93c29f679218f6167bb"}, 61 | ] 62 | 63 | [package.dependencies] 64 | numpy = "*" 65 | 66 | [[package]] 67 | name = "colorama" 68 | version = "0.4.6" 69 | description = "Cross-platform colored terminal text." 70 | optional = false 71 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 72 | files = [ 73 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, 74 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, 75 | ] 76 | 77 | [[package]] 78 | name = "contourpy" 79 | version = "1.2.0" 80 | description = "Python library for calculating contours of 2D quadrilateral grids" 81 | optional = false 82 | python-versions = ">=3.9" 83 | files = [ 84 | {file = "contourpy-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0274c1cb63625972c0c007ab14dd9ba9e199c36ae1a231ce45d725cbcbfd10a8"}, 85 | {file = "contourpy-1.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ab459a1cbbf18e8698399c595a01f6dcc5c138220ca3ea9e7e6126232d102bb4"}, 86 | {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fdd887f17c2f4572ce548461e4f96396681212d858cae7bd52ba3310bc6f00f"}, 87 | {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d16edfc3fc09968e09ddffada434b3bf989bf4911535e04eada58469873e28e"}, 88 | {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c203f617abc0dde5792beb586f827021069fb6d403d7f4d5c2b543d87edceb9"}, 89 | {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b69303ceb2e4d4f146bf82fda78891ef7bcd80c41bf16bfca3d0d7eb545448aa"}, 90 | {file = "contourpy-1.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:884c3f9d42d7218304bc74a8a7693d172685c84bd7ab2bab1ee567b769696df9"}, 91 | {file = "contourpy-1.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4a1b1208102be6e851f20066bf0e7a96b7d48a07c9b0cfe6d0d4545c2f6cadab"}, 92 | {file = "contourpy-1.2.0-cp310-cp310-win32.whl", hash = "sha256:34b9071c040d6fe45d9826cbbe3727d20d83f1b6110d219b83eb0e2a01d79488"}, 93 | {file = "contourpy-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:bd2f1ae63998da104f16a8b788f685e55d65760cd1929518fd94cd682bf03e41"}, 94 | {file = "contourpy-1.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dd10c26b4eadae44783c45ad6655220426f971c61d9b239e6f7b16d5cdaaa727"}, 95 | {file = "contourpy-1.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5c6b28956b7b232ae801406e529ad7b350d3f09a4fde958dfdf3c0520cdde0dd"}, 96 | {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebeac59e9e1eb4b84940d076d9f9a6cec0064e241818bcb6e32124cc5c3e377a"}, 97 | {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:139d8d2e1c1dd52d78682f505e980f592ba53c9f73bd6be102233e358b401063"}, 98 | {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e9dc350fb4c58adc64df3e0703ab076f60aac06e67d48b3848c23647ae4310e"}, 99 | {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18fc2b4ed8e4a8fe849d18dce4bd3c7ea637758c6343a1f2bae1e9bd4c9f4686"}, 100 | {file = "contourpy-1.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:16a7380e943a6d52472096cb7ad5264ecee36ed60888e2a3d3814991a0107286"}, 101 | {file = "contourpy-1.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8d8faf05be5ec8e02a4d86f616fc2a0322ff4a4ce26c0f09d9f7fb5330a35c95"}, 102 | {file = "contourpy-1.2.0-cp311-cp311-win32.whl", hash = "sha256:67b7f17679fa62ec82b7e3e611c43a016b887bd64fb933b3ae8638583006c6d6"}, 103 | {file = "contourpy-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:99ad97258985328b4f207a5e777c1b44a83bfe7cf1f87b99f9c11d4ee477c4de"}, 104 | {file = "contourpy-1.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:575bcaf957a25d1194903a10bc9f316c136c19f24e0985a2b9b5608bdf5dbfe0"}, 105 | {file = "contourpy-1.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9e6c93b5b2dbcedad20a2f18ec22cae47da0d705d454308063421a3b290d9ea4"}, 106 | {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:464b423bc2a009088f19bdf1f232299e8b6917963e2b7e1d277da5041f33a779"}, 107 | {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:68ce4788b7d93e47f84edd3f1f95acdcd142ae60bc0e5493bfd120683d2d4316"}, 108 | {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d7d1f8871998cdff5d2ff6a087e5e1780139abe2838e85b0b46b7ae6cc25399"}, 109 | {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e739530c662a8d6d42c37c2ed52a6f0932c2d4a3e8c1f90692ad0ce1274abe0"}, 110 | {file = "contourpy-1.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:247b9d16535acaa766d03037d8e8fb20866d054d3c7fbf6fd1f993f11fc60ca0"}, 111 | {file = "contourpy-1.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:461e3ae84cd90b30f8d533f07d87c00379644205b1d33a5ea03381edc4b69431"}, 112 | {file = "contourpy-1.2.0-cp312-cp312-win32.whl", hash = "sha256:1c2559d6cffc94890b0529ea7eeecc20d6fadc1539273aa27faf503eb4656d8f"}, 113 | {file = "contourpy-1.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:491b1917afdd8638a05b611a56d46587d5a632cabead889a5440f7c638bc6ed9"}, 114 | {file = "contourpy-1.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5fd1810973a375ca0e097dee059c407913ba35723b111df75671a1976efa04bc"}, 115 | {file = "contourpy-1.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:999c71939aad2780f003979b25ac5b8f2df651dac7b38fb8ce6c46ba5abe6ae9"}, 116 | {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7caf9b241464c404613512d5594a6e2ff0cc9cb5615c9475cc1d9b514218ae8"}, 117 | {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:266270c6f6608340f6c9836a0fb9b367be61dde0c9a9a18d5ece97774105ff3e"}, 118 | {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbd50d0a0539ae2e96e537553aff6d02c10ed165ef40c65b0e27e744a0f10af8"}, 119 | {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11f8d2554e52f459918f7b8e6aa20ec2a3bce35ce95c1f0ef4ba36fbda306df5"}, 120 | {file = "contourpy-1.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ce96dd400486e80ac7d195b2d800b03e3e6a787e2a522bfb83755938465a819e"}, 121 | {file = "contourpy-1.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6d3364b999c62f539cd403f8123ae426da946e142312a514162adb2addd8d808"}, 122 | {file = "contourpy-1.2.0-cp39-cp39-win32.whl", hash = "sha256:1c88dfb9e0c77612febebb6ac69d44a8d81e3dc60f993215425b62c1161353f4"}, 123 | {file = "contourpy-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:78e6ad33cf2e2e80c5dfaaa0beec3d61face0fb650557100ee36db808bfa6843"}, 124 | {file = "contourpy-1.2.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:be16975d94c320432657ad2402f6760990cb640c161ae6da1363051805fa8108"}, 125 | {file = "contourpy-1.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b95a225d4948b26a28c08307a60ac00fb8671b14f2047fc5476613252a129776"}, 126 | {file = "contourpy-1.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0d7e03c0f9a4f90dc18d4e77e9ef4ec7b7bbb437f7f675be8e530d65ae6ef956"}, 127 | {file = "contourpy-1.2.0.tar.gz", hash = "sha256:171f311cb758de7da13fc53af221ae47a5877be5a0843a9fe150818c51ed276a"}, 128 | ] 129 | 130 | [package.dependencies] 131 | numpy = ">=1.20,<2.0" 132 | 133 | [package.extras] 134 | bokeh = ["bokeh", "selenium"] 135 | docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] 136 | mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.6.1)", "types-Pillow"] 137 | test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] 138 | test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] 139 | 140 | [[package]] 141 | name = "cycler" 142 | version = "0.12.1" 143 | description = "Composable style cycles" 144 | optional = false 145 | python-versions = ">=3.8" 146 | files = [ 147 | {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"}, 148 | {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, 149 | ] 150 | 151 | [package.extras] 152 | docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] 153 | tests = ["pytest", "pytest-cov", "pytest-xdist"] 154 | 155 | [[package]] 156 | name = "fonttools" 157 | version = "4.47.0" 158 | description = "Tools to manipulate font files" 159 | optional = false 160 | python-versions = ">=3.8" 161 | files = [ 162 | {file = "fonttools-4.47.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2d2404107626f97a221dc1a65b05396d2bb2ce38e435f64f26ed2369f68675d9"}, 163 | {file = "fonttools-4.47.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c01f409be619a9a0f5590389e37ccb58b47264939f0e8d58bfa1f3ba07d22671"}, 164 | {file = "fonttools-4.47.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d986b66ff722ef675b7ee22fbe5947a41f60a61a4da15579d5e276d897fbc7fa"}, 165 | {file = "fonttools-4.47.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8acf6dd0434b211b3bd30d572d9e019831aae17a54016629fa8224783b22df8"}, 166 | {file = "fonttools-4.47.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:495369c660e0c27233e3c572269cbe520f7f4978be675f990f4005937337d391"}, 167 | {file = "fonttools-4.47.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c59227d7ba5b232281c26ae04fac2c73a79ad0e236bca5c44aae904a18f14faf"}, 168 | {file = "fonttools-4.47.0-cp310-cp310-win32.whl", hash = "sha256:59a6c8b71a245800e923cb684a2dc0eac19c56493e2f896218fcf2571ed28984"}, 169 | {file = "fonttools-4.47.0-cp310-cp310-win_amd64.whl", hash = "sha256:52c82df66201f3a90db438d9d7b337c7c98139de598d0728fb99dab9fd0495ca"}, 170 | {file = "fonttools-4.47.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:854421e328d47d70aa5abceacbe8eef231961b162c71cbe7ff3f47e235e2e5c5"}, 171 | {file = "fonttools-4.47.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:511482df31cfea9f697930f61520f6541185fa5eeba2fa760fe72e8eee5af88b"}, 172 | {file = "fonttools-4.47.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce0e2c88c8c985b7b9a7efcd06511fb0a1fe3ddd9a6cd2895ef1dbf9059719d7"}, 173 | {file = "fonttools-4.47.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7a0a8848726956e9d9fb18c977a279013daadf0cbb6725d2015a6dd57527992"}, 174 | {file = "fonttools-4.47.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e869da810ae35afb3019baa0d0306cdbab4760a54909c89ad8904fa629991812"}, 175 | {file = "fonttools-4.47.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dd23848f877c3754f53a4903fb7a593ed100924f9b4bff7d5a4e2e8a7001ae11"}, 176 | {file = "fonttools-4.47.0-cp311-cp311-win32.whl", hash = "sha256:bf1810635c00f7c45d93085611c995fc130009cec5abdc35b327156aa191f982"}, 177 | {file = "fonttools-4.47.0-cp311-cp311-win_amd64.whl", hash = "sha256:61df4dee5d38ab65b26da8efd62d859a1eef7a34dcbc331299a28e24d04c59a7"}, 178 | {file = "fonttools-4.47.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e3f4d61f3a8195eac784f1d0c16c0a3105382c1b9a74d99ac4ba421da39a8826"}, 179 | {file = "fonttools-4.47.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:174995f7b057e799355b393e97f4f93ef1f2197cbfa945e988d49b2a09ecbce8"}, 180 | {file = "fonttools-4.47.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea592e6a09b71cb7a7661dd93ac0b877a6228e2d677ebacbad0a4d118494c86d"}, 181 | {file = "fonttools-4.47.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40bdbe90b33897d9cc4a39f8e415b0fcdeae4c40a99374b8a4982f127ff5c767"}, 182 | {file = "fonttools-4.47.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:843509ae9b93db5aaf1a6302085e30bddc1111d31e11d724584818f5b698f500"}, 183 | {file = "fonttools-4.47.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9acfa1cdc479e0dde528b61423855913d949a7f7fe09e276228298fef4589540"}, 184 | {file = "fonttools-4.47.0-cp312-cp312-win32.whl", hash = "sha256:66c92ec7f95fd9732550ebedefcd190a8d81beaa97e89d523a0d17198a8bda4d"}, 185 | {file = "fonttools-4.47.0-cp312-cp312-win_amd64.whl", hash = "sha256:e8fa20748de55d0021f83754b371432dca0439e02847962fc4c42a0e444c2d78"}, 186 | {file = "fonttools-4.47.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c75e19971209fbbce891ebfd1b10c37320a5a28e8d438861c21d35305aedb81c"}, 187 | {file = "fonttools-4.47.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e79f1a3970d25f692bbb8c8c2637e621a66c0d60c109ab48d4a160f50856deff"}, 188 | {file = "fonttools-4.47.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:562681188c62c024fe2c611b32e08b8de2afa00c0c4e72bed47c47c318e16d5c"}, 189 | {file = "fonttools-4.47.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a77a60315c33393b2bd29d538d1ef026060a63d3a49a9233b779261bad9c3f71"}, 190 | {file = "fonttools-4.47.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b4fabb8cc9422efae1a925160083fdcbab8fdc96a8483441eb7457235df625bd"}, 191 | {file = "fonttools-4.47.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2a78dba8c2a1e9d53a0fb5382979f024200dc86adc46a56cbb668a2249862fda"}, 192 | {file = "fonttools-4.47.0-cp38-cp38-win32.whl", hash = "sha256:e6b968543fde4119231c12c2a953dcf83349590ca631ba8216a8edf9cd4d36a9"}, 193 | {file = "fonttools-4.47.0-cp38-cp38-win_amd64.whl", hash = "sha256:4a9a51745c0439516d947480d4d884fa18bd1458e05b829e482b9269afa655bc"}, 194 | {file = "fonttools-4.47.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:62d8ddb058b8e87018e5dc26f3258e2c30daad4c87262dfeb0e2617dd84750e6"}, 195 | {file = "fonttools-4.47.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5dde0eab40faaa5476133123f6a622a1cc3ac9b7af45d65690870620323308b4"}, 196 | {file = "fonttools-4.47.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4da089f6dfdb822293bde576916492cd708c37c2501c3651adde39804630538"}, 197 | {file = "fonttools-4.47.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:253bb46bab970e8aae254cebf2ae3db98a4ef6bd034707aa68a239027d2b198d"}, 198 | {file = "fonttools-4.47.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1193fb090061efa2f9e2d8d743ae9850c77b66746a3b32792324cdce65784154"}, 199 | {file = "fonttools-4.47.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:084511482dd265bce6dca24c509894062f0117e4e6869384d853f46c0e6d43be"}, 200 | {file = "fonttools-4.47.0-cp39-cp39-win32.whl", hash = "sha256:97620c4af36e4c849e52661492e31dc36916df12571cb900d16960ab8e92a980"}, 201 | {file = "fonttools-4.47.0-cp39-cp39-win_amd64.whl", hash = "sha256:e77bdf52185bdaf63d39f3e1ac3212e6cfa3ab07d509b94557a8902ce9c13c82"}, 202 | {file = "fonttools-4.47.0-py3-none-any.whl", hash = "sha256:d6477ba902dd2d7adda7f0fd3bfaeb92885d45993c9e1928c9f28fc3961415f7"}, 203 | {file = "fonttools-4.47.0.tar.gz", hash = "sha256:ec13a10715eef0e031858c1c23bfaee6cba02b97558e4a7bfa089dba4a8c2ebf"}, 204 | ] 205 | 206 | [package.extras] 207 | all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] 208 | graphite = ["lz4 (>=1.7.4.2)"] 209 | interpolatable = ["munkres", "pycairo", "scipy"] 210 | lxml = ["lxml (>=4.0,<5)"] 211 | pathops = ["skia-pathops (>=0.5.0)"] 212 | plot = ["matplotlib"] 213 | repacker = ["uharfbuzz (>=0.23.0)"] 214 | symfont = ["sympy"] 215 | type1 = ["xattr"] 216 | ufo = ["fs (>=2.2.0,<3)"] 217 | unicode = ["unicodedata2 (>=15.1.0)"] 218 | woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] 219 | 220 | [[package]] 221 | name = "importlib-resources" 222 | version = "6.1.1" 223 | description = "Read resources from Python packages" 224 | optional = false 225 | python-versions = ">=3.8" 226 | files = [ 227 | {file = "importlib_resources-6.1.1-py3-none-any.whl", hash = "sha256:e8bf90d8213b486f428c9c39714b920041cb02c184686a3dee24905aaa8105d6"}, 228 | {file = "importlib_resources-6.1.1.tar.gz", hash = "sha256:3893a00122eafde6894c59914446a512f728a0c1a45f9bb9b63721b6bacf0b4a"}, 229 | ] 230 | 231 | [package.dependencies] 232 | zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} 233 | 234 | [package.extras] 235 | docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] 236 | testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff", "zipp (>=3.17)"] 237 | 238 | [[package]] 239 | name = "iniconfig" 240 | version = "2.0.0" 241 | description = "brain-dead simple config-ini parsing" 242 | optional = false 243 | python-versions = ">=3.7" 244 | files = [ 245 | {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, 246 | {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, 247 | ] 248 | 249 | [[package]] 250 | name = "kiwisolver" 251 | version = "1.4.5" 252 | description = "A fast implementation of the Cassowary constraint solver" 253 | optional = false 254 | python-versions = ">=3.7" 255 | files = [ 256 | {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:05703cf211d585109fcd72207a31bb170a0f22144d68298dc5e61b3c946518af"}, 257 | {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:146d14bebb7f1dc4d5fbf74f8a6cb15ac42baadee8912eb84ac0b3b2a3dc6ac3"}, 258 | {file = "kiwisolver-1.4.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ef7afcd2d281494c0a9101d5c571970708ad911d028137cd558f02b851c08b4"}, 259 | {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9eaa8b117dc8337728e834b9c6e2611f10c79e38f65157c4c38e9400286f5cb1"}, 260 | {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff"}, 261 | {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39b42c68602539407884cf70d6a480a469b93b81b7701378ba5e2328660c847a"}, 262 | {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa12042de0171fad672b6c59df69106d20d5596e4f87b5e8f76df757a7c399aa"}, 263 | {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a40773c71d7ccdd3798f6489aaac9eee213d566850a9533f8d26332d626b82c"}, 264 | {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:19df6e621f6d8b4b9c4d45f40a66839294ff2bb235e64d2178f7522d9170ac5b"}, 265 | {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:83d78376d0d4fd884e2c114d0621624b73d2aba4e2788182d286309ebdeed770"}, 266 | {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e391b1f0a8a5a10ab3b9bb6afcfd74f2175f24f8975fb87ecae700d1503cdee0"}, 267 | {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:852542f9481f4a62dbb5dd99e8ab7aedfeb8fb6342349a181d4036877410f525"}, 268 | {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59edc41b24031bc25108e210c0def6f6c2191210492a972d585a06ff246bb79b"}, 269 | {file = "kiwisolver-1.4.5-cp310-cp310-win32.whl", hash = "sha256:a6aa6315319a052b4ee378aa171959c898a6183f15c1e541821c5c59beaa0238"}, 270 | {file = "kiwisolver-1.4.5-cp310-cp310-win_amd64.whl", hash = "sha256:d0ef46024e6a3d79c01ff13801cb19d0cad7fd859b15037aec74315540acc276"}, 271 | {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:11863aa14a51fd6ec28688d76f1735f8f69ab1fabf388851a595d0721af042f5"}, 272 | {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ab3919a9997ab7ef2fbbed0cc99bb28d3c13e6d4b1ad36e97e482558a91be90"}, 273 | {file = "kiwisolver-1.4.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fcc700eadbbccbf6bc1bcb9dbe0786b4b1cb91ca0dcda336eef5c2beed37b797"}, 274 | {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dfdd7c0b105af050eb3d64997809dc21da247cf44e63dc73ff0fd20b96be55a9"}, 275 | {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76c6a5964640638cdeaa0c359382e5703e9293030fe730018ca06bc2010c4437"}, 276 | {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbea0db94288e29afcc4c28afbf3a7ccaf2d7e027489c449cf7e8f83c6346eb9"}, 277 | {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ceec1a6bc6cab1d6ff5d06592a91a692f90ec7505d6463a88a52cc0eb58545da"}, 278 | {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:040c1aebeda72197ef477a906782b5ab0d387642e93bda547336b8957c61022e"}, 279 | {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f91de7223d4c7b793867797bacd1ee53bfe7359bd70d27b7b58a04efbb9436c8"}, 280 | {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:faae4860798c31530dd184046a900e652c95513796ef51a12bc086710c2eec4d"}, 281 | {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b0157420efcb803e71d1b28e2c287518b8808b7cf1ab8af36718fd0a2c453eb0"}, 282 | {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:06f54715b7737c2fecdbf140d1afb11a33d59508a47bf11bb38ecf21dc9ab79f"}, 283 | {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fdb7adb641a0d13bdcd4ef48e062363d8a9ad4a182ac7647ec88f695e719ae9f"}, 284 | {file = "kiwisolver-1.4.5-cp311-cp311-win32.whl", hash = "sha256:bb86433b1cfe686da83ce32a9d3a8dd308e85c76b60896d58f082136f10bffac"}, 285 | {file = "kiwisolver-1.4.5-cp311-cp311-win_amd64.whl", hash = "sha256:6c08e1312a9cf1074d17b17728d3dfce2a5125b2d791527f33ffbe805200a355"}, 286 | {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:32d5cf40c4f7c7b3ca500f8985eb3fb3a7dfc023215e876f207956b5ea26632a"}, 287 | {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f846c260f483d1fd217fe5ed7c173fb109efa6b1fc8381c8b7552c5781756192"}, 288 | {file = "kiwisolver-1.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ff5cf3571589b6d13bfbfd6bcd7a3f659e42f96b5fd1c4830c4cf21d4f5ef45"}, 289 | {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7269d9e5f1084a653d575c7ec012ff57f0c042258bf5db0954bf551c158466e7"}, 290 | {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da802a19d6e15dffe4b0c24b38b3af68e6c1a68e6e1d8f30148c83864f3881db"}, 291 | {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3aba7311af82e335dd1e36ffff68aaca609ca6290c2cb6d821a39aa075d8e3ff"}, 292 | {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763773d53f07244148ccac5b084da5adb90bfaee39c197554f01b286cf869228"}, 293 | {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2270953c0d8cdab5d422bee7d2007f043473f9d2999631c86a223c9db56cbd16"}, 294 | {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d099e745a512f7e3bbe7249ca835f4d357c586d78d79ae8f1dcd4d8adeb9bda9"}, 295 | {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:74db36e14a7d1ce0986fa104f7d5637aea5c82ca6326ed0ec5694280942d1162"}, 296 | {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e5bab140c309cb3a6ce373a9e71eb7e4873c70c2dda01df6820474f9889d6d4"}, 297 | {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0f114aa76dc1b8f636d077979c0ac22e7cd8f3493abbab152f20eb8d3cda71f3"}, 298 | {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:88a2df29d4724b9237fc0c6eaf2a1adae0cdc0b3e9f4d8e7dc54b16812d2d81a"}, 299 | {file = "kiwisolver-1.4.5-cp312-cp312-win32.whl", hash = "sha256:72d40b33e834371fd330fb1472ca19d9b8327acb79a5821d4008391db8e29f20"}, 300 | {file = "kiwisolver-1.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:2c5674c4e74d939b9d91dda0fae10597ac7521768fec9e399c70a1f27e2ea2d9"}, 301 | {file = "kiwisolver-1.4.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a2b053a0ab7a3960c98725cfb0bf5b48ba82f64ec95fe06f1d06c99b552e130"}, 302 | {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cd32d6c13807e5c66a7cbb79f90b553642f296ae4518a60d8d76243b0ad2898"}, 303 | {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59ec7b7c7e1a61061850d53aaf8e93db63dce0c936db1fda2658b70e4a1be709"}, 304 | {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da4cfb373035def307905d05041c1d06d8936452fe89d464743ae7fb8371078b"}, 305 | {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2400873bccc260b6ae184b2b8a4fec0e4082d30648eadb7c3d9a13405d861e89"}, 306 | {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1b04139c4236a0f3aff534479b58f6f849a8b351e1314826c2d230849ed48985"}, 307 | {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:4e66e81a5779b65ac21764c295087de82235597a2293d18d943f8e9e32746265"}, 308 | {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7931d8f1f67c4be9ba1dd9c451fb0eeca1a25b89e4d3f89e828fe12a519b782a"}, 309 | {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b3f7e75f3015df442238cca659f8baa5f42ce2a8582727981cbfa15fee0ee205"}, 310 | {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:bbf1d63eef84b2e8c89011b7f2235b1e0bf7dacc11cac9431fc6468e99ac77fb"}, 311 | {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4c380469bd3f970ef677bf2bcba2b6b0b4d5c75e7a020fb863ef75084efad66f"}, 312 | {file = "kiwisolver-1.4.5-cp37-cp37m-win32.whl", hash = "sha256:9408acf3270c4b6baad483865191e3e582b638b1654a007c62e3efe96f09a9a3"}, 313 | {file = "kiwisolver-1.4.5-cp37-cp37m-win_amd64.whl", hash = "sha256:5b94529f9b2591b7af5f3e0e730a4e0a41ea174af35a4fd067775f9bdfeee01a"}, 314 | {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:11c7de8f692fc99816e8ac50d1d1aef4f75126eefc33ac79aac02c099fd3db71"}, 315 | {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:53abb58632235cd154176ced1ae8f0d29a6657aa1aa9decf50b899b755bc2b93"}, 316 | {file = "kiwisolver-1.4.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:88b9f257ca61b838b6f8094a62418421f87ac2a1069f7e896c36a7d86b5d4c29"}, 317 | {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3195782b26fc03aa9c6913d5bad5aeb864bdc372924c093b0f1cebad603dd712"}, 318 | {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc579bf0f502e54926519451b920e875f433aceb4624a3646b3252b5caa9e0b6"}, 319 | {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a580c91d686376f0f7c295357595c5a026e6cbc3d77b7c36e290201e7c11ecb"}, 320 | {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cfe6ab8da05c01ba6fbea630377b5da2cd9bcbc6338510116b01c1bc939a2c18"}, 321 | {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d2e5a98f0ec99beb3c10e13b387f8db39106d53993f498b295f0c914328b1333"}, 322 | {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a51a263952b1429e429ff236d2f5a21c5125437861baeed77f5e1cc2d2c7c6da"}, 323 | {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3edd2fa14e68c9be82c5b16689e8d63d89fe927e56debd6e1dbce7a26a17f81b"}, 324 | {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:74d1b44c6cfc897df648cc9fdaa09bc3e7679926e6f96df05775d4fb3946571c"}, 325 | {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:76d9289ed3f7501012e05abb8358bbb129149dbd173f1f57a1bf1c22d19ab7cc"}, 326 | {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:92dea1ffe3714fa8eb6a314d2b3c773208d865a0e0d35e713ec54eea08a66250"}, 327 | {file = "kiwisolver-1.4.5-cp38-cp38-win32.whl", hash = "sha256:5c90ae8c8d32e472be041e76f9d2f2dbff4d0b0be8bd4041770eddb18cf49a4e"}, 328 | {file = "kiwisolver-1.4.5-cp38-cp38-win_amd64.whl", hash = "sha256:c7940c1dc63eb37a67721b10d703247552416f719c4188c54e04334321351ced"}, 329 | {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9407b6a5f0d675e8a827ad8742e1d6b49d9c1a1da5d952a67d50ef5f4170b18d"}, 330 | {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15568384086b6df3c65353820a4473575dbad192e35010f622c6ce3eebd57af9"}, 331 | {file = "kiwisolver-1.4.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0dc9db8e79f0036e8173c466d21ef18e1befc02de8bf8aa8dc0813a6dc8a7046"}, 332 | {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cdc8a402aaee9a798b50d8b827d7ecf75edc5fb35ea0f91f213ff927c15f4ff0"}, 333 | {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6c3bd3cde54cafb87d74d8db50b909705c62b17c2099b8f2e25b461882e544ff"}, 334 | {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:955e8513d07a283056b1396e9a57ceddbd272d9252c14f154d450d227606eb54"}, 335 | {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:346f5343b9e3f00b8db8ba359350eb124b98c99efd0b408728ac6ebf38173958"}, 336 | {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9098e0049e88c6a24ff64545cdfc50807818ba6c1b739cae221bbbcbc58aad3"}, 337 | {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:00bd361b903dc4bbf4eb165f24d1acbee754fce22ded24c3d56eec268658a5cf"}, 338 | {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7b8b454bac16428b22560d0a1cf0a09875339cab69df61d7805bf48919415901"}, 339 | {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f1d072c2eb0ad60d4c183f3fb44ac6f73fb7a8f16a2694a91f988275cbf352f9"}, 340 | {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:31a82d498054cac9f6d0b53d02bb85811185bcb477d4b60144f915f3b3126342"}, 341 | {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6512cb89e334e4700febbffaaa52761b65b4f5a3cf33f960213d5656cea36a77"}, 342 | {file = "kiwisolver-1.4.5-cp39-cp39-win32.whl", hash = "sha256:9db8ea4c388fdb0f780fe91346fd438657ea602d58348753d9fb265ce1bca67f"}, 343 | {file = "kiwisolver-1.4.5-cp39-cp39-win_amd64.whl", hash = "sha256:59415f46a37f7f2efeec758353dd2eae1b07640d8ca0f0c42548ec4125492635"}, 344 | {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5c7b3b3a728dc6faf3fc372ef24f21d1e3cee2ac3e9596691d746e5a536de920"}, 345 | {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:620ced262a86244e2be10a676b646f29c34537d0d9cc8eb26c08f53d98013390"}, 346 | {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:378a214a1e3bbf5ac4a8708304318b4f890da88c9e6a07699c4ae7174c09a68d"}, 347 | {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf7be1207676ac608a50cd08f102f6742dbfc70e8d60c4db1c6897f62f71523"}, 348 | {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ba55dce0a9b8ff59495ddd050a0225d58bd0983d09f87cfe2b6aec4f2c1234e4"}, 349 | {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd32ea360bcbb92d28933fc05ed09bffcb1704ba3fc7942e81db0fd4f81a7892"}, 350 | {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5e7139af55d1688f8b960ee9ad5adafc4ac17c1c473fe07133ac092310d76544"}, 351 | {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dced8146011d2bc2e883f9bd68618b8247387f4bbec46d7392b3c3b032640126"}, 352 | {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9bf3325c47b11b2e51bca0824ea217c7cd84491d8ac4eefd1e409705ef092bd"}, 353 | {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5794cf59533bc3f1b1c821f7206a3617999db9fbefc345360aafe2e067514929"}, 354 | {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e368f200bbc2e4f905b8e71eb38b3c04333bddaa6a2464a6355487b02bb7fb09"}, 355 | {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d706eba36b4c4d5bc6c6377bb6568098765e990cfc21ee16d13963fab7b3e7"}, 356 | {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85267bd1aa8880a9c88a8cb71e18d3d64d2751a790e6ca6c27b8ccc724bcd5ad"}, 357 | {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210ef2c3a1f03272649aff1ef992df2e724748918c4bc2d5a90352849eb40bea"}, 358 | {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11d011a7574eb3b82bcc9c1a1d35c1d7075677fdd15de527d91b46bd35e935ee"}, 359 | {file = "kiwisolver-1.4.5.tar.gz", hash = "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec"}, 360 | ] 361 | 362 | [[package]] 363 | name = "matplotlib" 364 | version = "3.8.2" 365 | description = "Python plotting package" 366 | optional = false 367 | python-versions = ">=3.9" 368 | files = [ 369 | {file = "matplotlib-3.8.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:09796f89fb71a0c0e1e2f4bdaf63fb2cefc84446bb963ecdeb40dfee7dfa98c7"}, 370 | {file = "matplotlib-3.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6f9c6976748a25e8b9be51ea028df49b8e561eed7809146da7a47dbecebab367"}, 371 | {file = "matplotlib-3.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b78e4f2cedf303869b782071b55fdde5987fda3038e9d09e58c91cc261b5ad18"}, 372 | {file = "matplotlib-3.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e208f46cf6576a7624195aa047cb344a7f802e113bb1a06cfd4bee431de5e31"}, 373 | {file = "matplotlib-3.8.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:46a569130ff53798ea5f50afce7406e91fdc471ca1e0e26ba976a8c734c9427a"}, 374 | {file = "matplotlib-3.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:830f00640c965c5b7f6bc32f0d4ce0c36dfe0379f7dd65b07a00c801713ec40a"}, 375 | {file = "matplotlib-3.8.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d86593ccf546223eb75a39b44c32788e6f6440d13cfc4750c1c15d0fcb850b63"}, 376 | {file = "matplotlib-3.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9a5430836811b7652991939012f43d2808a2db9b64ee240387e8c43e2e5578c8"}, 377 | {file = "matplotlib-3.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9576723858a78751d5aacd2497b8aef29ffea6d1c95981505877f7ac28215c6"}, 378 | {file = "matplotlib-3.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ba9cbd8ac6cf422f3102622b20f8552d601bf8837e49a3afed188d560152788"}, 379 | {file = "matplotlib-3.8.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:03f9d160a29e0b65c0790bb07f4f45d6a181b1ac33eb1bb0dd225986450148f0"}, 380 | {file = "matplotlib-3.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:3773002da767f0a9323ba1a9b9b5d00d6257dbd2a93107233167cfb581f64717"}, 381 | {file = "matplotlib-3.8.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:4c318c1e95e2f5926fba326f68177dee364aa791d6df022ceb91b8221bd0a627"}, 382 | {file = "matplotlib-3.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:091275d18d942cf1ee9609c830a1bc36610607d8223b1b981c37d5c9fc3e46a4"}, 383 | {file = "matplotlib-3.8.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b0f3b8ea0e99e233a4bcc44590f01604840d833c280ebb8fe5554fd3e6cfe8d"}, 384 | {file = "matplotlib-3.8.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7b1704a530395aaf73912be741c04d181f82ca78084fbd80bc737be04848331"}, 385 | {file = "matplotlib-3.8.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:533b0e3b0c6768eef8cbe4b583731ce25a91ab54a22f830db2b031e83cca9213"}, 386 | {file = "matplotlib-3.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:0f4fc5d72b75e2c18e55eb32292659cf731d9d5b312a6eb036506304f4675630"}, 387 | {file = "matplotlib-3.8.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:deaed9ad4da0b1aea77fe0aa0cebb9ef611c70b3177be936a95e5d01fa05094f"}, 388 | {file = "matplotlib-3.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:172f4d0fbac3383d39164c6caafd3255ce6fa58f08fc392513a0b1d3b89c4f89"}, 389 | {file = "matplotlib-3.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7d36c2209d9136cd8e02fab1c0ddc185ce79bc914c45054a9f514e44c787917"}, 390 | {file = "matplotlib-3.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5864bdd7da445e4e5e011b199bb67168cdad10b501750367c496420f2ad00843"}, 391 | {file = "matplotlib-3.8.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ef8345b48e95cee45ff25192ed1f4857273117917a4dcd48e3905619bcd9c9b8"}, 392 | {file = "matplotlib-3.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:7c48d9e221b637c017232e3760ed30b4e8d5dfd081daf327e829bf2a72c731b4"}, 393 | {file = "matplotlib-3.8.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:aa11b3c6928a1e496c1a79917d51d4cd5d04f8a2e75f21df4949eeefdf697f4b"}, 394 | {file = "matplotlib-3.8.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1095fecf99eeb7384dabad4bf44b965f929a5f6079654b681193edf7169ec20"}, 395 | {file = "matplotlib-3.8.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:bddfb1db89bfaa855912261c805bd0e10218923cc262b9159a49c29a7a1c1afa"}, 396 | {file = "matplotlib-3.8.2.tar.gz", hash = "sha256:01a978b871b881ee76017152f1f1a0cbf6bd5f7b8ff8c96df0df1bd57d8755a1"}, 397 | ] 398 | 399 | [package.dependencies] 400 | contourpy = ">=1.0.1" 401 | cycler = ">=0.10" 402 | fonttools = ">=4.22.0" 403 | importlib-resources = {version = ">=3.2.0", markers = "python_version < \"3.10\""} 404 | kiwisolver = ">=1.3.1" 405 | numpy = ">=1.21,<2" 406 | packaging = ">=20.0" 407 | pillow = ">=8" 408 | pyparsing = ">=2.3.1" 409 | python-dateutil = ">=2.7" 410 | 411 | [[package]] 412 | name = "numpy" 413 | version = "1.26.2" 414 | description = "Fundamental package for array computing in Python" 415 | optional = false 416 | python-versions = ">=3.9" 417 | files = [ 418 | {file = "numpy-1.26.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3703fc9258a4a122d17043e57b35e5ef1c5a5837c3db8be396c82e04c1cf9b0f"}, 419 | {file = "numpy-1.26.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cc392fdcbd21d4be6ae1bb4475a03ce3b025cd49a9be5345d76d7585aea69440"}, 420 | {file = "numpy-1.26.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36340109af8da8805d8851ef1d74761b3b88e81a9bd80b290bbfed61bd2b4f75"}, 421 | {file = "numpy-1.26.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bcc008217145b3d77abd3e4d5ef586e3bdfba8fe17940769f8aa09b99e856c00"}, 422 | {file = "numpy-1.26.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3ced40d4e9e18242f70dd02d739e44698df3dcb010d31f495ff00a31ef6014fe"}, 423 | {file = "numpy-1.26.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b272d4cecc32c9e19911891446b72e986157e6a1809b7b56518b4f3755267523"}, 424 | {file = "numpy-1.26.2-cp310-cp310-win32.whl", hash = "sha256:22f8fc02fdbc829e7a8c578dd8d2e15a9074b630d4da29cda483337e300e3ee9"}, 425 | {file = "numpy-1.26.2-cp310-cp310-win_amd64.whl", hash = "sha256:26c9d33f8e8b846d5a65dd068c14e04018d05533b348d9eaeef6c1bd787f9919"}, 426 | {file = "numpy-1.26.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b96e7b9c624ef3ae2ae0e04fa9b460f6b9f17ad8b4bec6d7756510f1f6c0c841"}, 427 | {file = "numpy-1.26.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aa18428111fb9a591d7a9cc1b48150097ba6a7e8299fb56bdf574df650e7d1f1"}, 428 | {file = "numpy-1.26.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06fa1ed84aa60ea6ef9f91ba57b5ed963c3729534e6e54055fc151fad0423f0a"}, 429 | {file = "numpy-1.26.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96ca5482c3dbdd051bcd1fce8034603d6ebfc125a7bd59f55b40d8f5d246832b"}, 430 | {file = "numpy-1.26.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:854ab91a2906ef29dc3925a064fcd365c7b4da743f84b123002f6139bcb3f8a7"}, 431 | {file = "numpy-1.26.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f43740ab089277d403aa07567be138fc2a89d4d9892d113b76153e0e412409f8"}, 432 | {file = "numpy-1.26.2-cp311-cp311-win32.whl", hash = "sha256:a2bbc29fcb1771cd7b7425f98b05307776a6baf43035d3b80c4b0f29e9545186"}, 433 | {file = "numpy-1.26.2-cp311-cp311-win_amd64.whl", hash = "sha256:2b3fca8a5b00184828d12b073af4d0fc5fdd94b1632c2477526f6bd7842d700d"}, 434 | {file = "numpy-1.26.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a4cd6ed4a339c21f1d1b0fdf13426cb3b284555c27ac2f156dfdaaa7e16bfab0"}, 435 | {file = "numpy-1.26.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5d5244aabd6ed7f312268b9247be47343a654ebea52a60f002dc70c769048e75"}, 436 | {file = "numpy-1.26.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a3cdb4d9c70e6b8c0814239ead47da00934666f668426fc6e94cce869e13fd7"}, 437 | {file = "numpy-1.26.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa317b2325f7aa0a9471663e6093c210cb2ae9c0ad824732b307d2c51983d5b6"}, 438 | {file = "numpy-1.26.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:174a8880739c16c925799c018f3f55b8130c1f7c8e75ab0a6fa9d41cab092fd6"}, 439 | {file = "numpy-1.26.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f79b231bf5c16b1f39c7f4875e1ded36abee1591e98742b05d8a0fb55d8a3eec"}, 440 | {file = "numpy-1.26.2-cp312-cp312-win32.whl", hash = "sha256:4a06263321dfd3598cacb252f51e521a8cb4b6df471bb12a7ee5cbab20ea9167"}, 441 | {file = "numpy-1.26.2-cp312-cp312-win_amd64.whl", hash = "sha256:b04f5dc6b3efdaab541f7857351aac359e6ae3c126e2edb376929bd3b7f92d7e"}, 442 | {file = "numpy-1.26.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4eb8df4bf8d3d90d091e0146f6c28492b0be84da3e409ebef54349f71ed271ef"}, 443 | {file = "numpy-1.26.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1a13860fdcd95de7cf58bd6f8bc5a5ef81c0b0625eb2c9a783948847abbef2c2"}, 444 | {file = "numpy-1.26.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64308ebc366a8ed63fd0bf426b6a9468060962f1a4339ab1074c228fa6ade8e3"}, 445 | {file = "numpy-1.26.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baf8aab04a2c0e859da118f0b38617e5ee65d75b83795055fb66c0d5e9e9b818"}, 446 | {file = "numpy-1.26.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d73a3abcac238250091b11caef9ad12413dab01669511779bc9b29261dd50210"}, 447 | {file = "numpy-1.26.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b361d369fc7e5e1714cf827b731ca32bff8d411212fccd29ad98ad622449cc36"}, 448 | {file = "numpy-1.26.2-cp39-cp39-win32.whl", hash = "sha256:bd3f0091e845164a20bd5a326860c840fe2af79fa12e0469a12768a3ec578d80"}, 449 | {file = "numpy-1.26.2-cp39-cp39-win_amd64.whl", hash = "sha256:2beef57fb031dcc0dc8fa4fe297a742027b954949cabb52a2a376c144e5e6060"}, 450 | {file = "numpy-1.26.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1cc3d5029a30fb5f06704ad6b23b35e11309491c999838c31f124fee32107c79"}, 451 | {file = "numpy-1.26.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94cc3c222bb9fb5a12e334d0479b97bb2df446fbe622b470928f5284ffca3f8d"}, 452 | {file = "numpy-1.26.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fe6b44fb8fcdf7eda4ef4461b97b3f63c466b27ab151bec2366db8b197387841"}, 453 | {file = "numpy-1.26.2.tar.gz", hash = "sha256:f65738447676ab5777f11e6bbbdb8ce11b785e105f690bc45966574816b6d3ea"}, 454 | ] 455 | 456 | [[package]] 457 | name = "packaging" 458 | version = "23.2" 459 | description = "Core utilities for Python packages" 460 | optional = false 461 | python-versions = ">=3.7" 462 | files = [ 463 | {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, 464 | {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, 465 | ] 466 | 467 | [[package]] 468 | name = "pillow" 469 | version = "10.1.0" 470 | description = "Python Imaging Library (Fork)" 471 | optional = false 472 | python-versions = ">=3.8" 473 | files = [ 474 | {file = "Pillow-10.1.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1ab05f3db77e98f93964697c8efc49c7954b08dd61cff526b7f2531a22410106"}, 475 | {file = "Pillow-10.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6932a7652464746fcb484f7fc3618e6503d2066d853f68a4bd97193a3996e273"}, 476 | {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f63b5a68daedc54c7c3464508d8c12075e56dcfbd42f8c1bf40169061ae666"}, 477 | {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0949b55eb607898e28eaccb525ab104b2d86542a85c74baf3a6dc24002edec2"}, 478 | {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ae88931f93214777c7a3aa0a8f92a683f83ecde27f65a45f95f22d289a69e593"}, 479 | {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b0eb01ca85b2361b09480784a7931fc648ed8b7836f01fb9241141b968feb1db"}, 480 | {file = "Pillow-10.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d27b5997bdd2eb9fb199982bb7eb6164db0426904020dc38c10203187ae2ff2f"}, 481 | {file = "Pillow-10.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7df5608bc38bd37ef585ae9c38c9cd46d7c81498f086915b0f97255ea60c2818"}, 482 | {file = "Pillow-10.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:41f67248d92a5e0a2076d3517d8d4b1e41a97e2df10eb8f93106c89107f38b57"}, 483 | {file = "Pillow-10.1.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1fb29c07478e6c06a46b867e43b0bcdb241b44cc52be9bc25ce5944eed4648e7"}, 484 | {file = "Pillow-10.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2cdc65a46e74514ce742c2013cd4a2d12e8553e3a2563c64879f7c7e4d28bce7"}, 485 | {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50d08cd0a2ecd2a8657bd3d82c71efd5a58edb04d9308185d66c3a5a5bed9610"}, 486 | {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:062a1610e3bc258bff2328ec43f34244fcec972ee0717200cb1425214fe5b839"}, 487 | {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:61f1a9d247317fa08a308daaa8ee7b3f760ab1809ca2da14ecc88ae4257d6172"}, 488 | {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a646e48de237d860c36e0db37ecaecaa3619e6f3e9d5319e527ccbc8151df061"}, 489 | {file = "Pillow-10.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:47e5bf85b80abc03be7455c95b6d6e4896a62f6541c1f2ce77a7d2bb832af262"}, 490 | {file = "Pillow-10.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a92386125e9ee90381c3369f57a2a50fa9e6aa8b1cf1d9c4b200d41a7dd8e992"}, 491 | {file = "Pillow-10.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:0f7c276c05a9767e877a0b4c5050c8bee6a6d960d7f0c11ebda6b99746068c2a"}, 492 | {file = "Pillow-10.1.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:a89b8312d51715b510a4fe9fc13686283f376cfd5abca8cd1c65e4c76e21081b"}, 493 | {file = "Pillow-10.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:00f438bb841382b15d7deb9a05cc946ee0f2c352653c7aa659e75e592f6fa17d"}, 494 | {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d929a19f5469b3f4df33a3df2983db070ebb2088a1e145e18facbc28cae5b27"}, 495 | {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a92109192b360634a4489c0c756364c0c3a2992906752165ecb50544c251312"}, 496 | {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:0248f86b3ea061e67817c47ecbe82c23f9dd5d5226200eb9090b3873d3ca32de"}, 497 | {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9882a7451c680c12f232a422730f986a1fcd808da0fd428f08b671237237d651"}, 498 | {file = "Pillow-10.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1c3ac5423c8c1da5928aa12c6e258921956757d976405e9467c5f39d1d577a4b"}, 499 | {file = "Pillow-10.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:806abdd8249ba3953c33742506fe414880bad78ac25cc9a9b1c6ae97bedd573f"}, 500 | {file = "Pillow-10.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:eaed6977fa73408b7b8a24e8b14e59e1668cfc0f4c40193ea7ced8e210adf996"}, 501 | {file = "Pillow-10.1.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:fe1e26e1ffc38be097f0ba1d0d07fcade2bcfd1d023cda5b29935ae8052bd793"}, 502 | {file = "Pillow-10.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7a7e3daa202beb61821c06d2517428e8e7c1aab08943e92ec9e5755c2fc9ba5e"}, 503 | {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24fadc71218ad2b8ffe437b54876c9382b4a29e030a05a9879f615091f42ffc2"}, 504 | {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1d323703cfdac2036af05191b969b910d8f115cf53093125e4058f62012c9a"}, 505 | {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:912e3812a1dbbc834da2b32299b124b5ddcb664ed354916fd1ed6f193f0e2d01"}, 506 | {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:7dbaa3c7de82ef37e7708521be41db5565004258ca76945ad74a8e998c30af8d"}, 507 | {file = "Pillow-10.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9d7bc666bd8c5a4225e7ac71f2f9d12466ec555e89092728ea0f5c0c2422ea80"}, 508 | {file = "Pillow-10.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:baada14941c83079bf84c037e2d8b7506ce201e92e3d2fa0d1303507a8538212"}, 509 | {file = "Pillow-10.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:2ef6721c97894a7aa77723740a09547197533146fba8355e86d6d9a4a1056b14"}, 510 | {file = "Pillow-10.1.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0a026c188be3b443916179f5d04548092e253beb0c3e2ee0a4e2cdad72f66099"}, 511 | {file = "Pillow-10.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:04f6f6149f266a100374ca3cc368b67fb27c4af9f1cc8cb6306d849dcdf12616"}, 512 | {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb40c011447712d2e19cc261c82655f75f32cb724788df315ed992a4d65696bb"}, 513 | {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a8413794b4ad9719346cd9306118450b7b00d9a15846451549314a58ac42219"}, 514 | {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c9aeea7b63edb7884b031a35305629a7593272b54f429a9869a4f63a1bf04c34"}, 515 | {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b4005fee46ed9be0b8fb42be0c20e79411533d1fd58edabebc0dd24626882cfd"}, 516 | {file = "Pillow-10.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4d0152565c6aa6ebbfb1e5d8624140a440f2b99bf7afaafbdbf6430426497f28"}, 517 | {file = "Pillow-10.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d921bc90b1defa55c9917ca6b6b71430e4286fc9e44c55ead78ca1a9f9eba5f2"}, 518 | {file = "Pillow-10.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:cfe96560c6ce2f4c07d6647af2d0f3c54cc33289894ebd88cfbb3bcd5391e256"}, 519 | {file = "Pillow-10.1.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:937bdc5a7f5343d1c97dc98149a0be7eb9704e937fe3dc7140e229ae4fc572a7"}, 520 | {file = "Pillow-10.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1c25762197144e211efb5f4e8ad656f36c8d214d390585d1d21281f46d556ba"}, 521 | {file = "Pillow-10.1.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:afc8eef765d948543a4775f00b7b8c079b3321d6b675dde0d02afa2ee23000b4"}, 522 | {file = "Pillow-10.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:883f216eac8712b83a63f41b76ddfb7b2afab1b74abbb413c5df6680f071a6b9"}, 523 | {file = "Pillow-10.1.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b920e4d028f6442bea9a75b7491c063f0b9a3972520731ed26c83e254302eb1e"}, 524 | {file = "Pillow-10.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c41d960babf951e01a49c9746f92c5a7e0d939d1652d7ba30f6b3090f27e412"}, 525 | {file = "Pillow-10.1.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1fafabe50a6977ac70dfe829b2d5735fd54e190ab55259ec8aea4aaea412fa0b"}, 526 | {file = "Pillow-10.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3b834f4b16173e5b92ab6566f0473bfb09f939ba14b23b8da1f54fa63e4b623f"}, 527 | {file = "Pillow-10.1.0.tar.gz", hash = "sha256:e6bf8de6c36ed96c86ea3b6e1d5273c53f46ef518a062464cd7ef5dd2cf92e38"}, 528 | ] 529 | 530 | [package.extras] 531 | docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] 532 | tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] 533 | 534 | [[package]] 535 | name = "pluggy" 536 | version = "1.3.0" 537 | description = "plugin and hook calling mechanisms for python" 538 | optional = false 539 | python-versions = ">=3.8" 540 | files = [ 541 | {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, 542 | {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, 543 | ] 544 | 545 | [package.extras] 546 | dev = ["pre-commit", "tox"] 547 | testing = ["pytest", "pytest-benchmark"] 548 | 549 | [[package]] 550 | name = "py" 551 | version = "1.11.0" 552 | description = "library with cross-python path, ini-parsing, io, code, log facilities" 553 | optional = false 554 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 555 | files = [ 556 | {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, 557 | {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, 558 | ] 559 | 560 | [[package]] 561 | name = "pyparsing" 562 | version = "3.1.1" 563 | description = "pyparsing module - Classes and methods to define and execute parsing grammars" 564 | optional = false 565 | python-versions = ">=3.6.8" 566 | files = [ 567 | {file = "pyparsing-3.1.1-py3-none-any.whl", hash = "sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb"}, 568 | {file = "pyparsing-3.1.1.tar.gz", hash = "sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db"}, 569 | ] 570 | 571 | [package.extras] 572 | diagrams = ["jinja2", "railroad-diagrams"] 573 | 574 | [[package]] 575 | name = "pytest" 576 | version = "6.2.5" 577 | description = "pytest: simple powerful testing with Python" 578 | optional = false 579 | python-versions = ">=3.6" 580 | files = [ 581 | {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, 582 | {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, 583 | ] 584 | 585 | [package.dependencies] 586 | atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} 587 | attrs = ">=19.2.0" 588 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 589 | iniconfig = "*" 590 | packaging = "*" 591 | pluggy = ">=0.12,<2.0" 592 | py = ">=1.8.2" 593 | toml = "*" 594 | 595 | [package.extras] 596 | testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] 597 | 598 | [[package]] 599 | name = "python-dateutil" 600 | version = "2.8.2" 601 | description = "Extensions to the standard Python datetime module" 602 | optional = false 603 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" 604 | files = [ 605 | {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, 606 | {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, 607 | ] 608 | 609 | [package.dependencies] 610 | six = ">=1.5" 611 | 612 | [[package]] 613 | name = "six" 614 | version = "1.16.0" 615 | description = "Python 2 and 3 compatibility utilities" 616 | optional = false 617 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" 618 | files = [ 619 | {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, 620 | {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, 621 | ] 622 | 623 | [[package]] 624 | name = "toml" 625 | version = "0.10.2" 626 | description = "Python Library for Tom's Obvious, Minimal Language" 627 | optional = false 628 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 629 | files = [ 630 | {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, 631 | {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, 632 | ] 633 | 634 | [[package]] 635 | name = "tqdm" 636 | version = "4.66.1" 637 | description = "Fast, Extensible Progress Meter" 638 | optional = false 639 | python-versions = ">=3.7" 640 | files = [ 641 | {file = "tqdm-4.66.1-py3-none-any.whl", hash = "sha256:d302b3c5b53d47bce91fea46679d9c3c6508cf6332229aa1e7d8653723793386"}, 642 | {file = "tqdm-4.66.1.tar.gz", hash = "sha256:d88e651f9db8d8551a62556d3cff9e3034274ca5d66e93197cf2490e2dcb69c7"}, 643 | ] 644 | 645 | [package.dependencies] 646 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 647 | 648 | [package.extras] 649 | dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"] 650 | notebook = ["ipywidgets (>=6)"] 651 | slack = ["slack-sdk"] 652 | telegram = ["requests"] 653 | 654 | [[package]] 655 | name = "zipp" 656 | version = "3.17.0" 657 | description = "Backport of pathlib-compatible object wrapper for zip files" 658 | optional = false 659 | python-versions = ">=3.8" 660 | files = [ 661 | {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"}, 662 | {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"}, 663 | ] 664 | 665 | [package.extras] 666 | docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] 667 | testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] 668 | 669 | [metadata] 670 | lock-version = "2.0" 671 | python-versions = "^3.9" 672 | content-hash = "5e3a8b71c1d10601d5e0c2e8e72d1ea2cd79f51cbe48d1f7512dd3fc591030c2" 673 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "complexcgr" 3 | version = "0.8.0" 4 | description = "complex Chaos Game Representation for DNA" 5 | authors = ["Jorge Avila "] 6 | maintainers = ["Jorge Avila "] 7 | repository = "https://github.com/AlgoLab/complexCGR" 8 | license = "MIT" 9 | 10 | [tool.poetry.dependencies] 11 | python = "^3.9" 12 | tqdm = "^4.61.2" 13 | matplotlib = "^3.4.2" 14 | Pillow = "^10.0" 15 | numpy = "^1.22.3" 16 | biopython = "^1.79" 17 | 18 | [tool.poetry.dev-dependencies] 19 | pytest = "^6.2.4" 20 | 21 | [build-system] 22 | requires = ["poetry-core>=1.0.0"] 23 | build-backend = "poetry.core.masonry.api" 24 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlgoLab/complexCGR/930a3804af8d43f81db3a383390ad56d5afaa72d/tests/__init__.py -------------------------------------------------------------------------------- /tests/test_cgr.py: -------------------------------------------------------------------------------- 1 | from complexcgr import CGR 2 | 3 | def test_cgr(): 4 | "Encoding for each nucleotide" 5 | cgr = CGR() 6 | 7 | cgr.encode("A") 8 | assert cgr.cgr_coords.N == 1 9 | assert cgr.cgr_coords.x == 0.5 10 | assert cgr.cgr_coords.y == 0.5 11 | 12 | cgr.encode("C") 13 | assert cgr.cgr_coords.N == 1 14 | assert cgr.cgr_coords.x == -0.5 15 | assert cgr.cgr_coords.y == 0.5 16 | 17 | cgr.encode("G") 18 | assert cgr.cgr_coords.N == 1 19 | assert cgr.cgr_coords.x == -0.5 20 | assert cgr.cgr_coords.y == -0.5 21 | 22 | cgr.encode("T") 23 | assert cgr.cgr_coords.N == 1 24 | assert cgr.cgr_coords.x == 0.5 25 | assert cgr.cgr_coords.y == -0.5 26 | 27 | def test_cgr_decode(): 28 | "Decoding each nucleotide" 29 | cgr = CGR() 30 | 31 | assert cgr.decode(N=1,x=0.5,y=0.5) == "A" 32 | assert cgr.decode(N=1,x=-0.5,y=0.5) == "C" 33 | assert cgr.decode(N=1,x=-0.5,y=-0.5) == "G" 34 | assert cgr.decode(N=1,x=0.5,y=-0.5) == "T" -------------------------------------------------------------------------------- /tests/test_complexcgr.py: -------------------------------------------------------------------------------- 1 | from complexcgr import ( 2 | __version__, 3 | ComplexCGR, 4 | ) 5 | 6 | def test_version(): 7 | assert __version__ == '0.8.0' 8 | 9 | def test_complexCGR(): 10 | ccgr = ComplexCGR() 11 | 12 | # nucleotide A 13 | encode = ccgr.encode("A") 14 | assert encode.k == 0 15 | assert encode.N == 1 16 | 17 | 18 | # nucleotide C 19 | encode = ccgr.encode("C") 20 | assert encode.k == 1 21 | assert encode.N == 1 22 | 23 | 24 | # nucleotide G 25 | encode = ccgr.encode("G") 26 | assert encode.k == 2 27 | assert encode.N == 1 28 | 29 | 30 | # nucleotide T 31 | encode = ccgr.encode("T") 32 | assert encode.k == 3 33 | assert encode.N == 1 34 | 35 | def test_complexCGR_decode(): 36 | ccgr = ComplexCGR() 37 | 38 | # nucleotide A 39 | decode = ccgr.decode(k=0,N=1) 40 | assert decode == "A" 41 | 42 | 43 | # nucleotide C 44 | decode = ccgr.decode(k=1,N=1) 45 | assert decode == "C" 46 | 47 | 48 | # nucleotide G 49 | decode = ccgr.decode(k=2,N=1) 50 | assert decode == "G" 51 | 52 | 53 | # nucleotide T 54 | decode = ccgr.decode(k=3,N=1) 55 | assert decode == "T" 56 | 57 | def test_encode_decode_compatibility(): 58 | ccgr = ComplexCGR() 59 | 60 | seq = "ACGT" 61 | encode = ccgr.encode(seq) 62 | decode = ccgr.decode(encode.k, encode.N) 63 | assert seq == decode -------------------------------------------------------------------------------- /tests/test_complexfcgr.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlgoLab/complexCGR/930a3804af8d43f81db3a383390ad56d5afaa72d/tests/test_complexfcgr.py -------------------------------------------------------------------------------- /tests/test_complexfcgr_savefig.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | import random 3 | from complexcgr import ComplexFCGR 4 | 5 | BASEPATH = Path().parent.resolve() 6 | def test_savefig(): 7 | fcgr = ComplexFCGR(k=8) 8 | seq = "".join(random.choice("ACG") for _ in range(300_000)) 9 | fig = fcgr(seq) 10 | fcgr.save(fig, path=BASEPATH.joinpath("img/ACG-complexCGR.png")) 11 | -------------------------------------------------------------------------------- /tests/test_fcgr.py: -------------------------------------------------------------------------------- 1 | import random 2 | from complexcgr import FCGR 3 | 4 | def test_fcgr(): 5 | "frecuency matrix CGR" 6 | fcgr = FCGR(k=1) 7 | fcgr.count_kmers("ACGT") 8 | 9 | assert fcgr.freq_kmer.get("A") == 1 10 | assert fcgr.freq_kmer.get("C") == 1 11 | assert fcgr.freq_kmer.get("G") == 1 12 | assert fcgr.freq_kmer.get("T") == 1 13 | 14 | def test_savefig(): 15 | fcgr = FCGR(k=8) 16 | # Generate a random sequence without T's 17 | seq = "".join(random.choice("ACG") for _ in range(30_000)) 18 | chaos = fcgr(seq) # an array with the probabilities of each k-mer 19 | fcgr.save_img(chaos, path="img/ACG.jpg") 20 | 21 | def test_savefig_16bits(): 22 | fcgr = FCGR(k=8, bits=16) 23 | # Generate a random sequence without T's 24 | seq = "".join(random.choice("ACG") for _ in range(30_000)) 25 | chaos = fcgr(seq) # an array with the probabilities of each k-mer 26 | fcgr.save_img(chaos, path="img/ACG_16bits.jpg") 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /tests/test_icgr.py: -------------------------------------------------------------------------------- 1 | from complexcgr import iCGR 2 | 3 | def test_cgr(): 4 | "Encoding for each nucleotide" 5 | cgr = iCGR() 6 | 7 | cgr.encode("A") 8 | assert cgr.cgr_coords.N == 1 9 | assert cgr.cgr_coords.x == 1 10 | assert cgr.cgr_coords.y == 1 11 | 12 | cgr.encode("C") 13 | assert cgr.cgr_coords.N == 1 14 | assert cgr.cgr_coords.x == -1 15 | assert cgr.cgr_coords.y == 1 16 | 17 | cgr.encode("G") 18 | assert cgr.cgr_coords.N == 1 19 | assert cgr.cgr_coords.x == -1 20 | assert cgr.cgr_coords.y == -1 21 | 22 | cgr.encode("T") 23 | assert cgr.cgr_coords.N == 1 24 | assert cgr.cgr_coords.x == 1 25 | assert cgr.cgr_coords.y == -1 26 | 27 | 28 | def test_cgr_decode(): 29 | "Decoding each nucleotide" 30 | cgr = iCGR() 31 | 32 | assert cgr.decode(N=1,x=1,y=1) == "A" 33 | assert cgr.decode(N=1,x=-1,y=1) == "C" 34 | assert cgr.decode(N=1,x=-1,y=-1) == "G" 35 | assert cgr.decode(N=1,x=1,y=-1) == "T" 36 | assert cgr.decode(N=4,x=3,y=-9) == "ACGT" --------------------------------------------------------------------------------