diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000..ee944f29 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,81 @@ +name: Documentation + +on: + workflow_dispatch: + push: + branches: ["main", "docs-*"] + +jobs: + build-docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: "3.10" + - name: Install dependencies + run: | + python -m pip install quartodoc + - uses: quarto-dev/quarto-actions/setup@v2 + with: + version: "1.2.475" + - name: Build docs + run: | + make docs-build + # push to netlify ------------------------------------------------------- + + # set release name ---- + + - name: Configure pull release name + if: ${{github.event_name == 'pull_request'}} + run: | + echo "RELEASE_NAME=pr-${PR_NUMBER}" >> $GITHUB_ENV + env: + PR_NUMBER: ${{ github.event.number }} + - name: Configure branch release name + if: ${{github.event_name != 'pull_request'}} + run: | + # use branch name, but replace slashes. E.g. feat/a -> feat-a + echo "RELEASE_NAME=${GITHUB_REF_NAME/\//-}" >> $GITHUB_ENV + # deploy ---- + + - name: Create Github Deployment + uses: bobheadxi/deployments@v0.4.3 + id: deployment + with: + step: start + token: ${{ secrets.GITHUB_TOKEN }} + env: ${{ env.RELEASE_NAME }} + ref: ${{ github.head_ref }} + transient: true + logs: 'https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}' + + - name: Netlify docs preview + run: | + npm install -g netlify-cli + # push main branch to production, others to preview -- + if [ "${ALIAS}" == "main" ]; then + netlify deploy --dir=docs/_build --alias="main" + else + netlify deploy --dir=docs/_build --alias="${ALIAS}" + fi + env: + NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} + NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} + ALIAS: ${{ steps.deployment.outputs.env }} + + - name: Update Github Deployment + uses: bobheadxi/deployments@v0.4.3 + if: ${{ always() }} + with: + step: finish + token: ${{ secrets.GITHUB_TOKEN }} + status: ${{ job.status }} + deployment_id: ${{ steps.deployment.outputs.deployment_id }} + env_url: 'https://${{ steps.deployment.outputs.env }}--molecularnodes.netlify.app' + logs: 'https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}' + - uses: peaceiris/actions-gh-pages@v3 + if: github.event_name == 'release' + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: docs/_build diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..2cf169be --- /dev/null +++ b/Makefile @@ -0,0 +1,3 @@ +docs-build: + cd docs && quartodoc build + quarto render docs diff --git a/docs/_quarto.yml b/docs/_quarto.yml index 0b57f172..d075fad5 100644 --- a/docs/_quarto.yml +++ b/docs/_quarto.yml @@ -1,6 +1,6 @@ project: type: website - output-dir: . + output-dir: _build website: title: "Molecular Nodes" diff --git a/docs/reference/coll.qmd b/docs/reference/coll.qmd deleted file mode 100644 index 6fe07ef5..00000000 --- a/docs/reference/coll.qmd +++ /dev/null @@ -1,30 +0,0 @@ -# coll { #coll } - -`` - -## Functions - -| Name | Description | -| --- | --- | -| [frames](#coll.frames) | Create a Collection for Frames of a Trajectory | -| [mn](#coll.mn) | Return the MolecularNodes Collection | - -## frames { #coll.frames } - -`frames(name='', parent=None, suffix='_frames')` - -Create a Collection for Frames of a Trajectory - -Args: - name (str, optional): Name of the collection for the frames. Defaults to "". - parent (_type_, optional): A blender collection which will become the parent - collection. Defaults to the MolecularNodes collection if None. - -## mn { #coll.mn } - -`mn()` - -Return the MolecularNodes Collection - -The collection called 'MolecularNodes' inside the Blender scene is returned. If the -collection does not exist first, it is created. \ No newline at end of file diff --git a/docs/reference/index.qmd b/docs/reference/index.qmd deleted file mode 100644 index 7fa5790e..00000000 --- a/docs/reference/index.qmd +++ /dev/null @@ -1,12 +0,0 @@ -# Function reference - -## Python API - -The Python code that powers Molecular Nodes under the hood. - -| | | -| --- | --- | -| [pkg](pkg.qmd#pkg) | Handling installation of external python packages inside of Blender's bundled python. | -| [load](load.qmd#load) | | -| [nodes](nodes.qmd#nodes) | | -| [coll](coll.qmd#coll) | | \ No newline at end of file diff --git a/docs/reference/load.qmd b/docs/reference/load.qmd deleted file mode 100644 index 0a9180a2..00000000 --- a/docs/reference/load.qmd +++ /dev/null @@ -1,115 +0,0 @@ -# load { #load } - -`` - -## Functions - -| Name | Description | -| --- | --- | -| [add_attribute](#load.add_attribute) | | -| [comp_secondary_structure](#load.comp_secondary_structure) | Use dihedrals to compute the secondary structure of proteins | -| [create_molecule](#load.create_molecule) | | -| [create_object](#load.create_object) | Creates a mesh with the given name in the given collection, from the supplied | -| [get_secondary_structure](#load.get_secondary_structure) | Gets the secondary structure annotation that is included in mmtf files and returns it as a numerical numpy array. | -| [load_star_file](#load.load_star_file) | | -| [molecule_esmfold](#load.molecule_esmfold) | | -| [molecule_local](#load.molecule_local) | | -| [molecule_rcsb](#load.molecule_rcsb) | | -| [open_structure_esm_fold](#load.open_structure_esm_fold) | | -| [open_structure_local_pdb](#load.open_structure_local_pdb) | | -| [open_structure_local_pdbx](#load.open_structure_local_pdbx) | | -| [open_structure_rcsb](#load.open_structure_rcsb) | | -| [pdb_get_b_factors](#load.pdb_get_b_factors) | Get a list, which contains a numpy array for each model containing the b-factors. | - -## add_attribute { #load.add_attribute } - -`add_attribute(object, name, data, type='FLOAT', domain='POINT', add=True)` - -## comp_secondary_structure { #load.comp_secondary_structure } - -`comp_secondary_structure(mol_array)` - -Use dihedrals to compute the secondary structure of proteins - -Through biotite built-in method derivated from P-SEA algorithm (Labesse 1997) -Returns an array with secondary structure for each atoms where: -- 0 = '' = non-protein or not assigned by biotite annotate_sse -- 1 = a = alpha helix -- 2 = b = beta sheet -- 3 = c = coil - -Inspired from https://www.biotite-python.org/examples/gallery/structure/transketolase_sse.html - -## create_molecule { #load.create_molecule } - -`create_molecule(mol_array, mol_name, center_molecule=False, file=None, calculate_ss=False, del_solvent=False, include_bonds=False, collection=None)` - -## create_object { #load.create_object } - -`create_object(name, collection, locations, bonds=\[\])` - -Creates a mesh with the given name in the given collection, from the supplied -values for the locations of vertices, and if supplied, bonds as edges. - -## get_secondary_structure { #load.get_secondary_structure } - -`get_secondary_structure(mol_array, file)` - -### Parameters: - -mol_array : numpy.array - The molecular coordinates array, from mmtf.get_structure() -file : mmtf.MMTFFile - The MMTF file containing the secondary structure information, from mmtf.MMTFFile.read() - - - -### Returns: - -atom_sse : numpy.array - Numerical numpy array representing the secondary structure of the molecule. - - - -### Description: - -This function uses the biotite.structure package to extract the secondary structure information from the MMTF file. -The resulting secondary structures are `1: Alpha Helix, 2: Beta-sheet, 3: loop`. - -## load_star_file { #load.load_star_file } - -`load_star_file(file_path, obj_name='NewStarInstances', node_tree=True, world_scale=0.01)` - -## molecule_esmfold { #load.molecule_esmfold } - -`molecule_esmfold(amino_acid_sequence, mol_name='Name', center_molecule=False, del_solvent=True, include_bonds=True, starting_style=0, setup_nodes=True)` - -## molecule_local { #load.molecule_local } - -`molecule_local(file_path, mol_name='Name', include_bonds=True, center_molecule=False, del_solvent=True, default_style=0, setup_nodes=True)` - -## molecule_rcsb { #load.molecule_rcsb } - -`molecule_rcsb(pdb_code, center_molecule=False, del_solvent=True, include_bonds=True, starting_style=0, setup_nodes=True)` - -## open_structure_esm_fold { #load.open_structure_esm_fold } - -`open_structure_esm_fold(amino_acid_sequence, include_bonds=True)` - -## open_structure_local_pdb { #load.open_structure_local_pdb } - -`open_structure_local_pdb(file_path, include_bonds=True)` - -## open_structure_local_pdbx { #load.open_structure_local_pdbx } - -`open_structure_local_pdbx(file_path, include_bonds=True)` - -## open_structure_rcsb { #load.open_structure_rcsb } - -`open_structure_rcsb(pdb_code, include_bonds=True)` - -## pdb_get_b_factors { #load.pdb_get_b_factors } - -`pdb_get_b_factors(file)` - -Get a list, which contains a numpy array for each model containing the b-factors. \ No newline at end of file diff --git a/docs/reference/nodes.qmd b/docs/reference/nodes.qmd deleted file mode 100644 index 276c3ea4..00000000 --- a/docs/reference/nodes.qmd +++ /dev/null @@ -1,105 +0,0 @@ -# nodes { #nodes } - -`` - -## Attributes - -| Name | Description | -| --- | --- | -| [socket_types](#nodes.socket_types) | | - -## Functions - -| Name | Description | -| --- | --- | -| [add_custom_node_group](#nodes.add_custom_node_group) | | -| [add_custom_node_group_to_node](#nodes.add_custom_node_group_to_node) | | -| [chain_color](#nodes.chain_color) | Given the input list of chain names, will create a node group which uses | -| [chain_selection](#nodes.chain_selection) | Given a an input_list, will create a node which takes an Integer input, | -| [create_custom_surface](#nodes.create_custom_surface) | | -| [create_starting_node_tree](#nodes.create_starting_node_tree) | | -| [create_starting_nodes_density](#nodes.create_starting_nodes_density) | | -| [create_starting_nodes_starfile](#nodes.create_starting_nodes_starfile) | | -| [gn_new_group_empty](#nodes.gn_new_group_empty) | | -| [mol_append_node](#nodes.mol_append_node) | | -| [mol_base_material](#nodes.mol_base_material) | Append MOL_atomic_material to the .blend file it it doesn't already exist, and return that material. | -| [resid_multiple_selection](#nodes.resid_multiple_selection) | Returns a node group that takes an integer input and creates a boolean | -| [rotation_matrix](#nodes.rotation_matrix) | Add a Rotation & Translation node from a 3x4 matrix. | - -## add_custom_node_group { #nodes.add_custom_node_group } - -`add_custom_node_group(parent_group, node_name, location=\[0, 0\], width=200)` - -## add_custom_node_group_to_node { #nodes.add_custom_node_group_to_node } - -`add_custom_node_group_to_node(parent_group, node_name, location=\[0, 0\], width=200)` - -## chain_color { #nodes.chain_color } - -`chain_color(node_name, input_list, label_prefix='Chain ')` - -Given the input list of chain names, will create a node group which uses -the chain_id named attribute to manually set the colours for each of the chains. - -## chain_selection { #nodes.chain_selection } - -`chain_selection(node_name, input_list, attribute, starting_value=0, label_prefix='')` - -Given a an input_list, will create a node which takes an Integer input, -and has a boolean tick box for each item in the input list. The outputs will -be the resulting selection and the inversion of the selection. -Can contain a prefix for the resulting labels. Mostly used for constructing -chain selections when required for specific proteins. - -## create_custom_surface { #nodes.create_custom_surface } - -`create_custom_surface(name, n_chains)` - -## create_starting_node_tree { #nodes.create_starting_node_tree } - -`create_starting_node_tree(obj, coll_frames, starting_style='atoms')` - -## create_starting_nodes_density { #nodes.create_starting_nodes_density } - -`create_starting_nodes_density(obj)` - -## create_starting_nodes_starfile { #nodes.create_starting_nodes_starfile } - -`create_starting_nodes_starfile(obj)` - -## gn_new_group_empty { #nodes.gn_new_group_empty } - -`gn_new_group_empty(name='Geometry Nodes')` - -## mol_append_node { #nodes.mol_append_node } - -`mol_append_node(node_name)` - -## mol_base_material { #nodes.mol_base_material } - -`mol_base_material()` - -Append MOL_atomic_material to the .blend file it it doesn't already exist, and return that material. - -## resid_multiple_selection { #nodes.resid_multiple_selection } - -`resid_multiple_selection(node_name, input_resid_string)` - -Returns a node group that takes an integer input and creates a boolean -tick box for each item in the input list. Outputs are the selected -residues and the inverse selection. Used for constructing chain -selections in specific proteins. - -## rotation_matrix { #nodes.rotation_matrix } - -`rotation_matrix(node_group, mat, location=\[0, 0\], world_scale=0.01)` - -Add a Rotation & Translation node from a 3x4 matrix. - -Args: - node_group (_type_): Parent node group to add this new node to. - mat (_type_): 3x4 rotation & translation matrix - location (list, optional): Position to add the node in the node tree. Defaults to [0,0]. - world_scale(float, optional): Scaling factor for the world. Defaults to 0.01. -Returns: - _type_: Newly created node tree. \ No newline at end of file diff --git a/docs/reference/pkg.qmd b/docs/reference/pkg.qmd deleted file mode 100644 index 5cf8f5db..00000000 --- a/docs/reference/pkg.qmd +++ /dev/null @@ -1,279 +0,0 @@ -# pkg { #pkg } - -`` - -Handling installation of external python packages inside of Blender's bundled python. - -## Attributes - -| Name | Description | -| --- | --- | -| [ADDON_DIR](#pkg.ADDON_DIR) | Folder for the addon on the local machine. | -| [PYPI_MIRROR](#pkg.PYPI_MIRROR) | Possible PyPi mirrors to install from. | - -## Functions - -| Name | Description | -| --- | --- | -| [get_pkgs](#pkg.get_pkgs) | Read a requirements file and extract package information into a dictionary. | -| [get_pypi_mirror_alias](#pkg.get_pypi_mirror_alias) | Get the available PyPI mirror aliases. | -| [install_all_packages](#pkg.install_all_packages) | Install all packages listed in the 'requirements.txt' file. | -| [install_package](#pkg.install_package) | Install a Python package and its dependencies using pip. | -| [is_available](#pkg.is_available) | Check if a given package is available with the specified version. | -| [is_current](#pkg.is_current) | Check if the specified package is the current version. | -| [process_pypi_mirror_to_url](#pkg.process_pypi_mirror_to_url) | Process a PyPI mirror provider and return the corresponding URL. | -| [run_python](#pkg.run_python) | Runs pip command using the specified command list and returns the command output. | -| [start_logging](#pkg.start_logging) | Configure and start logging to a file. | - -## get_pkgs { #pkg.get_pkgs } - -`get_pkgs(requirements=None)` - -Read a requirements file and extract package information into a dictionary. - -### Parameters - -| Name | Type | Description | Default | -|----------------|---------------|-------------------------------------------------------------------------------------------------------------------------------------------|-----------| -| `requirements` | str, optional | The path to the requirements file. If not provided, the function looks for a `requirements.txt` file in the same directory as the script. | `None` | - -### Returns - -| Type | Description | -|--------|----------------------------------------------------------------------------------------------------------------------------------------------------| -| dict | A dictionary containing package information. Each element of the dictionary is a dictionary containing the package name, version, and description. | - -### Example - -Given the following requirements file: -```python -Flask==1.1.2 # A micro web framework for Python -pandas==1.2.3 # A fast, powerful, flexible, and easy-to-use data analysis and manipulation tool -numpy==1.20.1 # Fundamental package for scientific computing -``` -The function would return the following dictionary: -```python -[ - { - "package": "Flask", - "version": "1.1.2", - "desc": "A micro web framework for Python" - }, - { - "package": "pandas", - "version": "1.2.3", - "desc": "A fast, powerful, flexible, and easy-to-use data analysis and manipulation tool" - }, - { - "package": "numpy", - "version": "1.20.1", - "desc": "Fundamental package for scientific computing" - } -] -``` - -## get_pypi_mirror_alias { #pkg.get_pypi_mirror_alias } - -`get_pypi_mirror_alias(self, context, edit_text)` - -Get the available PyPI mirror aliases. - -### Parameters - -| Name | Type | Description | Default | -|-------------|--------|------------------------------------------------|-----------| -| `self` | object | The object instance. | required | -| `context` | ... | The context parameter (description missing). | required | -| `edit_text` | ... | The edit_text parameter (description missing). | required | - -### Returns - -| Type | Description | -|-----------|-----------------------------------------------------| -| keys_view | A view object of the available PyPI mirror aliases. | - -## install_all_packages { #pkg.install_all_packages } - -`install_all_packages(pypi_mirror_provider='Default')` - -Install all packages listed in the 'requirements.txt' file. - -### Parameters - -| Name | Type | Description | Default | -|------------------------|---------------|------------------------------------------------------------------------------------------------------------------|-------------| -| `pypi_mirror_provider` | str, optional | The PyPI mirror to use for package installation. Defaults to 'Default', which uses the official PyPI repository. | `'Default'` | - -### Returns - -| Type | Description | -|--------|------------------------------------------------------------------------| -| list | A list of tuples containing the installation results for each package. | - -### Raises - -| Type | Description | -|-------------------|---------------------------------------------------| -| InstallationError | If there is an error during package installation. | - -### Example - -To install all packages listed in the 'requirements.txt' file, run the following command: -``` -install_all_packages(pypi_mirror_provider='https://pypi.org/simple/') -``` - -## install_package { #pkg.install_package } - -`install_package(package, pypi_mirror_provider='Default')` - -Install a Python package and its dependencies using pip. - -### Parameters - -| Name | Type | Description | Default | -|------------------------|---------------|------------------------------------------------------------------------|-------------| -| `package` | str | The name of the package to install. | required | -| `pypi_mirror_provider` | str, optional | The name/url of the PyPI mirror provider to use. Default is 'Default'. | `'Default'` | - -### Returns - -| Type | Description | -|--------|---------------| -| list | A list of tuples containing the command list, return code, stdout, and stderr -for each pip command run. | - -### Raises - -| Type | Description | -|------------|--------------------------------------| -| ValueError | If the package name is not provided. | - -### Example - -To install the package 'requests' from the PyPI mirror 'MyMirror', use: -``` -install_package('requests', 'MyMirror') -``` - -## is_available { #pkg.is_available } - -`is_available(package, version=None)` - -Check if a given package is available with the specified version. - -### Parameters - -| Name | Type | Description | Default | -|-----------|---------------|--------------------------------------|-----------| -| `package` | str | The name of the package to check. | required | -| `version` | str, optional | The version of the package to check. | `None` | - -### Returns - -| Type | Description | -|--------|-------------------------------------------------------------------------------| -| bool | True if the package with the specified version is available, False otherwise. | - -### Examples - -```python ->>> is_available('numpy', '1.20.1') -True -``` - -## is_current { #pkg.is_current } - -`is_current(package)` - -Check if the specified package is the current version. - -### Parameters - -| Name | Type | Description | Default | -|-----------|--------|-----------------------------------|-----------| -| `package` | str | The name of the package to check. | required | - -### Returns - -| Type | Description | -|--------|--------------------------------------------------------------| -| bool | True if the package is the current version, False otherwise. | - -## process_pypi_mirror_to_url { #pkg.process_pypi_mirror_to_url } - -`process_pypi_mirror_to_url(pypi_mirror_provider)` - -Process a PyPI mirror provider and return the corresponding URL. - -### Parameters - -| Name | Type | Description | Default | -|------------------------|--------|--------------------------------------|-----------| -| `pypi_mirror_provider` | str | The PyPI mirror provider to process. | required | - -### Returns - -| Type | Description | -|--------|-----------------------------| -| str | The URL of the PyPI mirror. | - -### Raises - -| Type | Description | -|------------|--------------------------------------------------| -| ValueError | If the provided PyPI mirror provider is invalid. | - -## run_python { #pkg.run_python } - -`run_python(cmd_list=None, mirror_url='', timeout=600)` - -Runs pip command using the specified command list and returns the command output. - -### Parameters - -| Name | Type | Description | Default | -|--------------|----------------|--------------------------------------------------------------------------------|-----------| -| `cmd_list` | list, optional | List of pip commands to be executed. Defaults to None. | `None` | -| `mirror_url` | str, optional | URL of a package repository mirror to be used for the command. Defaults to ''. | `''` | -| `timeout` | int, optional | Time in seconds to wait for the command to complete. Defaults to 600. | `600` | - -### Returns - -| Type | Description | -|--------|---------------| -| tuple | A tuple containing the command list, command return code, command standard output, -and command standard error. | - -### Example - -Install numpy using pip and print the command output -```python -cmd_list = ["-m", "pip", "install", "numpy"] -mirror_url = 'https://pypi.org/simple/' -cmd_output = run_python(cmd_list, mirror_url=mirror_url, timeout=300) -print(cmd_output) -``` - -## start_logging { #pkg.start_logging } - -`start_logging(logfile_name='side-packages-install')` - -Configure and start logging to a file. - -### Parameters - -| Name | Type | Description | Default | -|----------------|---------------|----------------------------------------------------------------|---------------------------| -| `logfile_name` | str, optional | The name of the log file. Defaults to 'side-packages-install'. | `'side-packages-install'` | - -### Returns - -| Type | Description | -|----------------|---------------------------------------------------------| -| logging.Logger | A Logger object that can be used to write log messages. | - -This function sets up a logging configuration with a specified log file name and logging level. -The log file will be created in the `ADDON_DIR/logs` directory. If the directory -does not exist, it will be created. The function returns a Logger object that can be used to -write log messages. \ No newline at end of file