From b7161b87bfe49450ebd4c50c5f184d231dfbb63e Mon Sep 17 00:00:00 2001 From: rice8y Date: Tue, 30 Jun 2026 07:51:21 +0900 Subject: [PATCH] typshade:0.1.3 --- packages/preview/typshade/0.1.3/LICENSE | 338 +++++ packages/preview/typshade/0.1.3/README.md | 206 +++ .../typshade/0.1.3/images/readme-overview.png | Bin 0 -> 159341 bytes .../0.1.3/images/readme-preview-1.png | Bin 0 -> 96938 bytes .../0.1.3/images/readme-preview-2.png | Bin 0 -> 107865 bytes .../0.1.3/images/readme-preview-3.png | Bin 0 -> 124013 bytes .../0.1.3/internal/engine/commands.typ | 24 + .../typshade/0.1.3/internal/engine/config.typ | 1045 ++++++++++++++ .../typshade/0.1.3/internal/engine/layout.typ | 394 +++++ .../0.1.3/internal/interface/analysis.typ | 185 +++ .../0.1.3/internal/interface/annotations.typ | 53 + .../0.1.3/internal/interface/controls.typ | 191 +++ .../0.1.3/internal/interface/data.typ | 18 + .../0.1.3/internal/interface/inspect.typ | 151 ++ .../0.1.3/internal/interface/presets.typ | 140 ++ .../0.1.3/internal/interface/recipes.typ | 726 ++++++++++ .../0.1.3/internal/interface/selection.typ | 64 + .../0.1.3/internal/interface/shade.typ | 163 +++ .../0.1.3/internal/interface/shortcuts.typ | 164 +++ .../0.1.3/internal/interface/tracks.typ | 77 + .../typshade/0.1.3/internal/model/logo.typ | 181 +++ .../typshade/0.1.3/internal/model/palette.typ | 460 ++++++ .../typshade/0.1.3/internal/model/parser.typ | 519 +++++++ .../typshade/0.1.3/internal/model/pdb.typ | 210 +++ .../0.1.3/internal/model/text-style.typ | 132 ++ .../0.1.3/internal/render/alignment.typ | 1280 +++++++++++++++++ .../0.1.3/internal/render/features.typ | 388 +++++ .../typshade/0.1.3/internal/render/graphs.typ | 626 ++++++++ .../typshade/0.1.3/internal/render/logos.typ | 160 +++ packages/preview/typshade/0.1.3/justfile | 64 + packages/preview/typshade/0.1.3/lib.typ | 15 + packages/preview/typshade/0.1.3/typst.toml | 11 + 32 files changed, 7985 insertions(+) create mode 100644 packages/preview/typshade/0.1.3/LICENSE create mode 100644 packages/preview/typshade/0.1.3/README.md create mode 100644 packages/preview/typshade/0.1.3/images/readme-overview.png create mode 100644 packages/preview/typshade/0.1.3/images/readme-preview-1.png create mode 100644 packages/preview/typshade/0.1.3/images/readme-preview-2.png create mode 100644 packages/preview/typshade/0.1.3/images/readme-preview-3.png create mode 100644 packages/preview/typshade/0.1.3/internal/engine/commands.typ create mode 100644 packages/preview/typshade/0.1.3/internal/engine/config.typ create mode 100644 packages/preview/typshade/0.1.3/internal/engine/layout.typ create mode 100644 packages/preview/typshade/0.1.3/internal/interface/analysis.typ create mode 100644 packages/preview/typshade/0.1.3/internal/interface/annotations.typ create mode 100644 packages/preview/typshade/0.1.3/internal/interface/controls.typ create mode 100644 packages/preview/typshade/0.1.3/internal/interface/data.typ create mode 100644 packages/preview/typshade/0.1.3/internal/interface/inspect.typ create mode 100644 packages/preview/typshade/0.1.3/internal/interface/presets.typ create mode 100644 packages/preview/typshade/0.1.3/internal/interface/recipes.typ create mode 100644 packages/preview/typshade/0.1.3/internal/interface/selection.typ create mode 100644 packages/preview/typshade/0.1.3/internal/interface/shade.typ create mode 100644 packages/preview/typshade/0.1.3/internal/interface/shortcuts.typ create mode 100644 packages/preview/typshade/0.1.3/internal/interface/tracks.typ create mode 100644 packages/preview/typshade/0.1.3/internal/model/logo.typ create mode 100644 packages/preview/typshade/0.1.3/internal/model/palette.typ create mode 100644 packages/preview/typshade/0.1.3/internal/model/parser.typ create mode 100644 packages/preview/typshade/0.1.3/internal/model/pdb.typ create mode 100644 packages/preview/typshade/0.1.3/internal/model/text-style.typ create mode 100644 packages/preview/typshade/0.1.3/internal/render/alignment.typ create mode 100644 packages/preview/typshade/0.1.3/internal/render/features.typ create mode 100644 packages/preview/typshade/0.1.3/internal/render/graphs.typ create mode 100644 packages/preview/typshade/0.1.3/internal/render/logos.typ create mode 100644 packages/preview/typshade/0.1.3/justfile create mode 100644 packages/preview/typshade/0.1.3/lib.typ create mode 100644 packages/preview/typshade/0.1.3/typst.toml diff --git a/packages/preview/typshade/0.1.3/LICENSE b/packages/preview/typshade/0.1.3/LICENSE new file mode 100644 index 0000000000..a66a55f980 --- /dev/null +++ b/packages/preview/typshade/0.1.3/LICENSE @@ -0,0 +1,338 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, see . + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Moe Ghoul, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. \ No newline at end of file diff --git a/packages/preview/typshade/0.1.3/README.md b/packages/preview/typshade/0.1.3/README.md new file mode 100644 index 0000000000..964f3ddc08 --- /dev/null +++ b/packages/preview/typshade/0.1.3/README.md @@ -0,0 +1,206 @@ +# Typshade + +![Typshade alignment overview](images/readme-overview.png) + +Typshade is a Typst package for visualizing multiple sequence alignments in bioinformatics. + +It provides a Typst-native interface centered on `shade(...)`, offering a readable and composable way to render alignments, add annotations, and incorporate logos, structure tracks, and graph tracks. + +Inspired by [TeXshade](https://ctan.org/pkg/texshade), Typshade rethinks alignment visualization with a focus on clarity, composability, and a Typst-native user experience. + +## Why Typshade? + +TeXshade is powerful, but its UI reflects TeX: many global commands, implicit state, and order-sensitive setup before the alignment is rendered. Typshade keeps the feature set while making the source read like a figure specification. + +TeXshade style: + +```latex +\begin{texshade}{alignment.msf} + \shadingmode[similar]{identical} + \shadingcolors{blues} + \residuesperline{45} + \setends{1}{80..125} + \showruler{top}{1} + \rulersteps{10} + \showconsensus{bottom} + \showsequencelogo{top} + \shaderegion{1}{NPA}{White}{BrickRed} + \feature{top}{1}{NXX[ST]N}{box[Yellow]}{motif} +\end{texshade} +``` + +Typshade style: + +```typst +#let alignment = read("alignment.msf", encoding: none) + +#shade( + alignment, + format: "msf", + figure: publication( + similarity: "blues", + region: "80..125", + logo: "charge", + motifs: ( + "NPA": (bg: "BrickRed", text: "active site"), + "NXX[ST]N": "motif", + ), + ), +) +``` + +The lower-level helpers are still available through `commands:` when you need precise control, but new documents can usually start from the kind of figure you want: publication figure, motif map, structure map, or logo analysis. + +## Quick Start + +```typst +#import "@preview/typshade:0.1.3": * + +#let alignment = read("alignment.msf", encoding: none) + +#shade( + alignment, + format: "msf", + theme: "screen", + figure: motif-map(auto), +) +``` + +`read(..., encoding: none)` remains supported on Typst 0.15 and later. On Typst 0.15 or later, you can additionally pass a resolved project path and let Typshade read the source inside the package: + +```typst +#shade(path("alignment.msf"), format: "msf", figure: motif-map(auto)) +``` + +## Preview + +Protein alignment with similarity shading, motif annotations, a ruler, +a conservation track, and a legend: + +![Protein alignment preview](images/readme-preview-1.png) + +Protein alignment with hydropathy-based functional coloring: + +![Hydropathy preview](images/readme-preview-2.png) + +Nucleotide alignment with DNA coloring, a sequence logo, a conservation track, +and a ruler: + +![DNA alignment preview](images/readme-preview-3.png) + +## Typst-Native Helpers + +- `shade(...)`: Named-option alignment renderer for new documents. +- `figure:`: Purpose-level recipe slot for complete figure designs. +- `publication`, `motif-map`, `structure-map`, `logo-analysis`, `overview`: High-level recipes. +- `similar`, `identical`, `diverse`, `functional`, `lines`, `window`, `ruler`, `consensus`, `logo`, `legend`: Compact command helpers; `lines(auto)` and `fit: "container"` fit the current Typst container. +- `auto-layout(...)`, `auto-page(...)`, and `fit: "page"`: Typst-aware line length and page-aware block splitting for long figures. +- `color-scheme`, `scoring-mode`, `sequence-window`: Small, readable option helpers. +- `ruler-track`, `consensus-track`, `sequence-logo`, `subfamily-logo`, `legend-track`: Track helpers. +- `structure-tracks(...)`: Adds topology/secondary-structure tracks from sidecar files. +- `shade-preset("publication" | "overview" | "logo" | "functional" | "structure")`: Reusable command bundles. +- `shade-theme("classic" | "print" | "screen" | "warm" | "nature")` and `visual-theme(...)`: Color/style bundles. +- `highlight`, `tint`, `emphasize`, `mark`, `motif`, `graph`: Readable command builders for common annotations; graph metrics include conservation, entropy, gap-fraction, coverage, identity, hydrophobicity, molecular weight, and charge. +- `select-range`, `select-motif`, `select-metric`, `select-and`, `select-or`, `select-not`, and `select-pad`: Composable Selection DSL values for windows, highlights, marks, graphs, and analysis helpers. +- `cell-style(ctx => ...)`: Data-driven per-cell styling with Typst functions. +- `pdb-point`, `pdb-line`, `pdb-plane`: Safer constructors for PDB selections. +- `alignment-position("left" | "center" | "right")`: Overrides the default left-aligned block placement. +- `alignment-summary(...)`, `alignment-debug(...)`, `cell-inspect(...)`, and `selection-preview(...)`: In-document inspection helpers. +- `sequence-list(...)` and `selection-table(...)`: Typst tables for data-aware reports. +- `percent-identity(...)`, `percent-similarity(...)`, and `similarity-table(...)`: Pairwise identity/similarity analysis. +- `alignment-data(...)` and `parse-alignment(...)`: Data access helpers for custom Typst logic. + +## TeXshade To Typshade + +| TeXshade idea | Typshade API | +|---|---| +| `texshade` environment | `shade(read("alignment.msf", encoding: none), format: "msf", figure: publication(...))`, or `shade(path("alignment.msf"), format: "msf", ...)` on Typst 0.15+ | +| `shadingmode`, `shadingcolors`, `threshold` | `similar`, `identical`, `diverse`, `functional`, or `scoring-mode`, `color-scheme`, `threshold` | +| `residuesperline`, `setends` | `lines`, `window`, `fit`, `auto-layout`, `auto-page`, or Selection DSL values with `sequence-window` | +| `shownames`, `shownumbering`, `showconsensus`, `showruler` | `names`, `numbers`, `consensus`, `ruler`, or the fine-grained track helpers | +| `showsequencelogo`, `showsubfamilylogo`, `showlegend` | `logo`, `subfamily-logo`, `legend` | +| `shaderegion`, `tintregion`, `emphregion`, `feature` | `highlight`, `tint`, `emphasize`, `mark`, `motif`, `graph` | +| `includeDSSP`, `includeSTRIDE`, `includeHMMTOP`, `includePHD*` | `structure-tracks`, `dssp-track`, `stride-track`, `hmmtop-track`, `phd-topology-track`, `phd-secondary-track` | +| font and spacing macros | `text-family`, `text-weight`, `text-posture`, `text-size`, `block-gap`, `feature-slot-space` | + +See the [full documentation](https://github.com/rice8y/typshade/blob/v0.1.3/docs/documentation.pdf) for the full guide and a larger correspondence table. + +## Smart Recipes + +Recipes inspect the alignment before rendering. For example, `motif-map(auto)` detects common motifs for the sequence type, focuses the region around them, chooses a readable line length, adds conservation when useful, and enables a logo only when the figure stays readable. Override any option when you need exact control. + +## Fine-Grained Control + +Macro-style command names are intentionally not part of the public API. Use Typst-shaped command helpers when you need detailed control: + +- Scoring: `threshold`, `weight-table`, `set-weight`, `gap-penalty`, `residue-style`, `functional-group`. +- Tracks: `names-track`, `numbering-track`, `consensus-name`, `consensus-symbols`, `ruler-name`, `ruler-marker`, `logo-color`. +- Sequence layout: `start-number`, `sequence-length`, `domain`, `hide-sequence`, `sequence-order`, `separation-line`. +- Features and structure: `feature-rule`, `feature-text-label`, `backtranslation-label`, `show-structure-types`, `structure-appearance`, `stride-track`, `dssp-track`, `hmmtop-track`, `phd-topology-track`, `phd-secondary-track`. +- Typography and spacing: `text-family`, `text-weight`, `text-posture`, `text-size`, `character-stretch`, `line-stretch`, `block-gap`, `feature-slot-space`. + +## Custom Control + +Use recipes when you know the purpose of the figure: + +```typst +#let alignment = read("alignment.msf", encoding: none) + +#shade( + alignment, + format: "msf", + figure: publication( + region: "80..125", + logo: "charge", + motifs: ( + "NPA": (bg: "BrickRed", text: "active site"), + "NXX[ST]N": "glycosylation", + ), + ), +) +``` + +Use `commands:` when you want to assemble visible parts yourself: + +```typst +#let alignment = read("alignment.msf", encoding: none) + +#shade( + alignment, + format: "msf", + preset: "publication", + theme: "screen", + commands: ( + similar(colors: "blues", threshold: 45), + lines(45), + window(1, "80..125"), + ruler("top", sequence: 1, every: 10), + consensus("bottom", name: "conservation"), + logo("top", colors: "charge"), + legend(), + highlight(1, "NPA", bg: "BrickRed"), + motif(1, "NXX[ST]N", text: "motif"), + graph("bottom", 1, "all", "conservation", kind: "color", options: ("ColdHot",)), + ), +) +``` + +You can also mix recipe output with explicit, reproducible helper lists: + +```typst +#let alignment = read("alignment.msf", encoding: none) + +#shade( + alignment, + format: "msf", + figure: publication(region: "80..125"), + commands: ( + highlight(1, "NXX[DE][KR]XXQ", fg: "White", bg: "BrickRed"), + sequence-logo(position: "top"), + ), +) +``` + +# License + +This project is distributed under the GPL v2 License. See [LICENSE](LICENSE) for details. diff --git a/packages/preview/typshade/0.1.3/images/readme-overview.png b/packages/preview/typshade/0.1.3/images/readme-overview.png new file mode 100644 index 0000000000000000000000000000000000000000..d6061b9d0e8f26fb6885df4d79411752da060592 GIT binary patch literal 159341 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

yKsk-^X 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%0D7f8IrQi1E*g9b}S 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

t>s{KI8soYZL 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 literal 0 HcmV?d00001 diff --git a/packages/preview/typshade/0.1.3/images/readme-preview-3.png b/packages/preview/typshade/0.1.3/images/readme-preview-3.png new file mode 100644 index 0000000000000000000000000000000000000000..ece3ee65a651bc42a4b5734fcdf851b9f8bcae88 GIT binary patch literal 124013 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

-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 _upper(group.trim())).filter(group => group != "") + } + value.map(group => _upper(str(group).trim())).filter(group => group != "") +} + +#let _ref-list(value) = { + if type(value) == str { + let out = () + for item in value.split(",") { + let trimmed = item.trim() + if trimmed == "" { + continue + } + let range-hit = trimmed.matches(regex("^(\\d+)\\-(\\d+)$")) + if range-hit.len() > 0 { + let start = int(range-hit.first().captures.at(0)) + let stop = int(range-hit.first().captures.at(1)) + let step = if start <= stop { 1 } else { -1 } + let current = start + while current != stop + step { + out.push(current) + current += step + } + } else { + out.push(trimmed) + } + } + return out + } + if type(value) == array { + return value + } + (value,) +} + +#let _type-list(value) = if type(value) == str { value.split(",").map(v => v.trim()).filter(v => v != "") } else { value } + +#let _hide-structure-types(config, filetype, types) = { + let remove = _type-list(types) + let kept = () + for item in config.at("structure-show").at(filetype, default: ()) { + if not remove.contains(item) { + kept.push(item) + } + } + config.at("structure-show").insert(filetype, kept) +} + +#let _default-config() = { + let config = ( + threshold: 50, + allmatch-threshold: 100, + weight-table: "identity", + custom-weights: (:), + gap-penalty: 0, + residues-per-line: 60, + auto-layout: ( + fit: none, + min: 1, + max: none, + ), + auto-page: ( + enabled: false, + blocks: none, + repeat-legend: false, + ), + font: "DejaVu Sans Mono", + font-families: ( + serif: "Times New Roman", + sans: "Arial", + ), + font-size: 9pt, + line-gap: 2pt, + block-gap: 8pt, + fixed-block-space: false, + char-stretch: 1.0, + numbering-width-digits: 4, + text-styles: _default-text-styles, + alignment: "left", + align-right-labels: false, + seq-type: none, + show-leading-gaps: true, + single-seq-shift: none, + keep-single-seq-gaps: false, + hide-residues: false, + hide-allmatch-positions: false, + hide-seqs: false, + no-shade: (), + sequence-names: (:), + hidden-names: (), + hidden-numbers: (), + sequence-name-colors: (:), + sequence-number-colors: (:), + names-color: "Black", + numbering-color: "Black", + start-numbers: (:), + sequence-lengths: (:), + allow-zero: false, + stop-char: "*", + names: ("show": true, "position": "left"), + numbering: ("show": true, "left": false, "right": true), + consensus: ( + "show": true, + "position": "bottom", + "scale": none, + "name": "consensus", + "source": "all", + "symbols": ("none": "", "conserved": "*", "allmatch": "!"), + "colors": ( + "none": (fg: "Black", bg: "White"), + "conserved": (fg: "Black", bg: "White"), + "allmatch": (fg: "Black", bg: "White"), + ), + ), + ruler: ("show": false, "position": "top", "sequence": 1, "steps": 10, "color": "Black"), + ruler-colors: ("top": "Black", "bottom": "Black"), + ruler-names: ("top": "", "bottom": ""), + ruler-name-colors: ("top": "Black", "bottom": "Black"), + ruler-labels: ("top": (:), "bottom": (:)), + ruler-spacing: ("top": 0pt, "bottom": 0pt), + ruler-rotation: ("top": false, "bottom": false), + gaps: ("char": ".", "fg": "Black", "bg": "White", "rule-thickness": 0.3pt), + shading: ("mode": "identical", "option": none, "scheme": "blues", "reference": none), + shading-schemes: (:), + tcoffee: ("source": none, "scores": (:)), + pep-groups: _pep-groups, + dna-groups: _dna-groups, + pep-sims: _pep-sims, + dna-sims: _dna-sims, + functional-groups: _functional-presets, + functional-style-overrides: (:), + functional-default: "charge", + residue-style: _default-style("identical"), + cell-styles: (), + sequence-logo: ("show": false, "position": "top", "colorset": none, "name": "logo", "scale": "leftright", "stretch": 1), + subfamily-logo: ("show": false, "position": "top", "colorset": none, "name": "subfamily", "negative-name": "remaining", "show-negatives": true), + logo-scale: ("show": true, "position": "leftright", "color": "Black"), + logo-colors: ("default": none, "map": (:)), + relevance: ("show": true, "color": "Black", "char": "*", "threshold": 0.1), + frequency-correction: false, + legend: ("show": false, "color": "Black", "dx": 0pt, "dy": 0pt), + captions: ("top": none, "bottom": none, "short": none), + separation-lines: (), + separation-space: 6pt, + bar-graph-stretch: ("default": 1.0), + color-scale-stretch: ("default": 1.0), + feature-style-names: (:), + feature-text-names: (:), + feature-style-name-colors: ("default": "Black"), + feature-text-name-colors: ("default": "Black"), + feature-slot-spacing: ( + ttttop: 0pt, + tttop: 0pt, + ttop: 0pt, + top: 0pt, + bottom: 0pt, + bbottom: 0pt, + bbbottom: 0pt, + bbbbottom: 0pt, + ), + subfamily: (), + structure-show: ( + "DSSP": ("alpha", "3-10", "pi", "beta"), + "STRIDE": ("alpha", "3-10", "pi", "beta"), + "PHDsec": ("alpha", "beta"), + "PHDtopo": ("internal", "external", "TM"), + "HMMTOP": ("TM"), + ), + structure-appearance: ( + "PHDtopo:internal": ("position": "bottom", "style": "-", "text": "int."), + "PHDtopo:external": ("position": "top", "style": ",-,", "text": "ext."), + "PHDtopo:TM": ("position": "top", "style": "box", "text": "TM"), + "HMMTOP:internal": ("position": "bottom", "style": "-", "text": "int."), + "HMMTOP:external": ("position": "top", "style": ",-,", "text": "ext."), + "HMMTOP:TM": ("position": "top", "style": "helix", "text": "TM"), + "PHDsec:alpha": ("position": "top", "style": "box", "text": "α\\numcount"), + "PHDsec:beta": ("position": "top", "style": "-->", "text": "β\\numcount"), + "STRIDE:alpha": ("position": "top", "style": "box:$\\alpha$\\numcount", "text": ""), + "STRIDE:3-10": ("position": "top", "style": "fill:$\\circ$", "text": "3-10"), + "STRIDE:pi": ("position": "top", "style": "---", "text": "π"), + "STRIDE:beta": ("position": "top", "style": "-->", "text": "β\\numcount"), + "STRIDE:bridge": ("position": "top", "style": "fill:$\\uparrow$", "text": ""), + "STRIDE:turn": ("position": "top", "style": ",-,", "text": "turn"), + "DSSP:alpha": ("position": "top", "style": "box:$\\alpha$\\numcount", "text": ""), + "DSSP:3-10": ("position": "top", "style": "fill:$\\circ$", "text": "3-10"), + "DSSP:pi": ("position": "top", "style": "---", "text": "π"), + "DSSP:beta": ("position": "top", "style": "-->", "text": "β\\numcount"), + "DSSP:bridge": ("position": "top", "style": "fill:$\\uparrow$", "text": ""), + "DSSP:turn": ("position": "top", "style": ",-,", "text": "turn"), + "DSSP:bend": ("position": "top", "style": "fill:$\\diamond$", "text": ""), + ), + dssp-second-column: true, + structure-data: (), + sequence-windows: (), + emph-default: "italic", + tint-default: "normal", + shade-regions: (), + tint-regions: (), + lower-regions: (), + emph-regions: (), + frame-regions: (), + hidden: (), + killed: (), + order: none, + features: (), + feature-rule: 0.5pt, + genetic-code: _standard-genetic-code, + backtranslation: ( + label-style: "alternating", + label-size: "tiny", + text-style: "horizontal", + text-size: "tiny", + ), + exported-consensus: none, + ) + _apply-shading-colors(config, "blues") + config +} + +#let _command(kind, fields) = { + let out = fields + out.insert("kind", kind) + out +} + +#let sequence-type(value) = _command("sequence-type", (value: value)) +#let scoring-mode(mode, option: none) = _command("scoring-mode", (mode: mode, option: option)) +#let color-scheme(name) = _command("color-scheme", (name: name)) +#let define-color-scheme(name) = _command("define-color-scheme", (name: name)) +#let threshold(value) = _command("threshold", (value: value)) +#let shade-all-residues() = _command("shade-all-residues", (:)) +#let all-match-threshold(value: 100) = _command("all-match-threshold", (value: value)) +#let disable-all-match-threshold() = _command("disable-all-match-threshold", (:)) +#let hide-all-match-positions() = _command("hide-all-match-positions", (:)) +#let show-all-match-positions() = _command("show-all-match-positions", (:)) +#let weight-table(name) = _command("weight-table", (name: name)) +#let set-weight(residue-a, residue-b, value) = _command("set-weight", (residue-a: residue-a, residue-b: residue-b, value: value)) +#let gap-penalty(value) = _command("gap-penalty", (value: value)) +#let residues-per-line(value) = _command("residues-per-line", (value: value)) +#let auto-layout(fit: "container", min: 1, max: none) = _command("auto-layout", (fit: fit, min: min, max: max)) +#let auto-page(blocks: auto, repeat-legend: true) = _command("auto-page", (blocks: blocks, repeat-legend: repeat-legend)) +#let numbering-track(position: "right", color: none) = _command("numbering-track", (position: position, color: color)) +#let no-numbering-track() = _command("no-numbering-track", (:)) +#let names-track(position: "left", color: none) = _command("names-track", (position: position, color: color)) +#let no-names-track() = _command("no-names-track", (:)) +#let sequence-name(sequence, name) = _command("sequence-name", (sequence: sequence, name: name)) +#let names-color(color) = _command("names-color", (color: color)) +#let sequence-name-color(sequences, color) = _command("sequence-name-color", (sequences: sequences, color: color)) +#let hide-sequence-name(sequences) = _command("hide-sequence-name", (sequences: sequences)) +#let numbering-color(color) = _command("numbering-color", (color: color)) +#let sequence-number-color(sequences, color) = _command("sequence-number-color", (sequences: sequences, color: color)) +#let hide-sequence-number(sequences) = _command("hide-sequence-number", (sequences: sequences)) +#let consensus-track(position: "bottom", scale: none, name: none) = _command("consensus-track", (position: position, scale: scale, name: name)) +#let no-consensus-track() = _command("no-consensus-track", (:)) +#let consensus-name(name) = _command("consensus-name", (name: name)) +#let language(name) = _command("language", (name: name)) +#let consensus-symbols(none-symbol, conserved-symbol, allmatch-symbol) = _command("consensus-symbols", ("none": none-symbol, conserved: conserved-symbol, allmatch: allmatch-symbol)) +#let consensus-colors(none-fg: "Black", none-bg: "White", conserved-fg: "Black", conserved-bg: "White", allmatch-fg: "Black", allmatch-bg: "White") = _command("consensus-colors", (none-fg: none-fg, none-bg: none-bg, conserved-fg: conserved-fg, conserved-bg: conserved-bg, allmatch-fg: allmatch-fg, allmatch-bg: allmatch-bg)) +#let residue-style(target, fg, bg, case: "upper", style: "normal") = _command("residue-style", (target: target, fg: fg, bg: bg, case: case, style: style)) +#let cell-style(callback) = _command("cell-style", (callback: callback)) +#let clear-functional-groups() = _command("clear-functional-groups", (:)) +#let functional-group(name, residues, fg, bg, case: "upper", style: "normal") = _command("functional-group", (name: name, residues: residues, fg: fg, bg: bg, case: case, style: style)) +#let functional-style(residue, fg, bg, case: "upper", style: "normal") = _command("functional-style", (residue: residue, fg: fg, bg: bg, case: case, style: style)) +#let ruler-track(position: "top", sequence: 1, steps: none, color: none) = _command("ruler-track", (position: position, sequence: sequence, steps: steps, color: color)) +#let no-ruler-track(position: none) = _command("no-ruler-track", (position: position)) +#let ruler-steps(value, position: none) = _command("ruler-steps", (value: value, position: position)) +#let ruler-color(color, position: none) = _command("ruler-color", (color: color, position: position)) +#let ruler-name(name, position: none) = _command("ruler-name", (name: name, position: position)) +#let ruler-name-color(color, position: none) = _command("ruler-name-color", (color: color, position: position)) +#let ruler-marker(number, text, position: none, color: none) = _command("ruler-marker", (number: number, text: text, position: position, color: color)) +#let ruler-space(value, position: none) = _command("ruler-space", (value: value, position: position)) +#let rotate-ruler(..args) = { + let positional = args.pos() + let position = if positional.len() > 0 { positional.first() } else { args.named().at("position", default: none) } + _command("rotate-ruler", (position: position)) +} +#let unrotate-ruler(..args) = { + let positional = args.pos() + let position = if positional.len() > 0 { positional.first() } else { args.named().at("position", default: none) } + _command("unrotate-ruler", (position: position)) +} +#let gap-char(symbol) = _command("gap-char", (symbol: symbol)) +#let gap-rule(thickness) = _command("gap-rule", (thickness: thickness)) +#let gap-colors(foreground, background) = _command("gap-colors", (foreground: foreground, background: background)) +#let stop-char(symbol) = _command("stop-char", (symbol: symbol)) +#let peptide-groups(groups) = _command("peptide-groups", (groups: groups)) +#let dna-groups(groups) = _command("dna-groups", (groups: groups)) +#let peptide-similarities(residue, similars) = _command("peptide-similarities", (residue: residue, similars: similars)) +#let dna-similarities(residue, similars) = _command("dna-similarities", (residue: residue, similars: similars)) +#let start-number(sequence, start, selection: none) = _command("start-number", (sequence: sequence, start: start, selection: selection)) +#let allow-zero-numbering() = _command("allow-zero-numbering", (:)) +#let disallow-zero-numbering() = _command("disallow-zero-numbering", (:)) +#let sequence-length(sequence, length) = _command("sequence-length", (sequence: sequence, length: length)) +#let sequence-window(sequence, selection, start: none) = _command("sequence-window", (sequence: sequence, selection: selection, start: start)) +#let domain(sequence, selection) = sequence-window(sequence, selection) +#let domain-gap-rule(thickness) = gap-rule(thickness) +#let domain-gap-colors(foreground, background) = gap-colors(foreground, background) +#let region-highlight(sequence, selection, ..args) = { + let positional = args.pos() + let named = args.named() + let bg = if positional.len() >= 2 { positional.at(1) } else { named.at("bg", default: none) } + let fg-or-scheme = if positional.len() >= 1 { positional.at(0) } else { named.at("fg-or-scheme", default: none) } + let scheme = named.at("scheme", default: none) + let resolved-scheme = if scheme != none { scheme } else if bg == none { fg-or-scheme } else { none } + let fg = if bg == none { named.at("fg", default: none) } else { fg-or-scheme } + _command("region-highlight", (sequence: sequence, selection: selection, scheme: resolved-scheme, fg: fg, bg: bg, all: named.at("apply-to-all", default: false))) +} +#let highlight-block(sequence, selection, ..args) = { + let command = region-highlight(sequence, selection, ..args) + command.insert("all", args.named().at("apply-to-all", default: true)) + command +} +#let region-color-scheme(sequence, selection, scheme) = region-highlight(sequence, selection, scheme: scheme, apply-to-all: true) +#let region-tint(sequence, selection, intensity: "medium") = _command("region-tint", (sequence: sequence, selection: selection, intensity: intensity)) +#let tint-block(sequence, selection, intensity: "medium") = region-tint(sequence, selection, intensity: intensity) +#let tint-default(effect) = _command("tint-default", (effect: effect)) +#let region-lower(sequence, selection) = _command("region-lower", (sequence: sequence, selection: selection)) +#let lower-block(sequence, selection) = region-lower(sequence, selection) +#let region-emphasis(sequence, selection, style: "italic") = _command("region-emphasis", (sequence: sequence, selection: selection, style: style)) +#let emphasis-block(sequence, selection, style: "italic") = region-emphasis(sequence, selection, style: style) +#let emphasis-default(style) = _command("emphasis-default", (style: style)) +#let frame-block(sequence, selection, color: "Red") = _command("frame-block", (sequence: sequence, selection: selection, color: color)) +#let hide-sequence(sequence) = _command("hide-sequence", (sequence: sequence)) +#let hide-all-sequences() = _command("hide-all-sequences", (:)) +#let show-all-sequences() = _command("show-all-sequences", (:)) +#let remove-sequence(sequence) = _command("remove-sequence", (sequence: sequence)) +#let no-shade(sequences) = _command("no-shade", (sequences: sequences)) +#let separation-line(sequence) = _command("separation-line", (sequence: sequence)) +#let sequence-order(order) = _command("sequence-order", (order: order)) +#let feature(position, sequence, selection, style: "", text: "") = _command("feature", (position: position, sequence: sequence, selection: selection, style: style, text: text)) +#let feature-rule(thickness) = _command("feature-rule", (thickness: thickness)) +#let codon(residue, triplets) = _command("codon", (residue: residue, triplets: triplets)) +#let genetic-code(name) = _command("genetic-code", (name: name)) +#let backtranslation-label(..args) = { + let positional = args.pos() + let style = if positional.len() > 0 { positional.last() } else { args.named().at("style", default: "alternating") } + let size = args.named().at("size", default: "tiny") + _command("backtranslation-label", (style: style, size: size)) +} +#let backtranslation-text(..args) = { + let positional = args.pos() + let style = if positional.len() > 0 { positional.last() } else { args.named().at("style", default: "horizontal") } + let size = args.named().at("size", default: "tiny") + _command("backtranslation-text", (style: style, size: size)) +} +#let feature-text-label(position, name) = _command("feature-text-label", (position: position, name: name)) +#let feature-style-label(position, name) = _command("feature-style-label", (position: position, name: name)) +#let hide-feature-text-label(position) = _command("hide-feature-text-label", (position: position)) +#let hide-feature-style-label(position) = _command("hide-feature-style-label", (position: position)) +#let hide-feature-text-labels() = _command("hide-feature-text-labels", (:)) +#let hide-feature-style-labels() = _command("hide-feature-style-labels", (:)) +#let feature-text-label-color(color) = _command("feature-text-label-color", (color: color)) +#let feature-style-label-color(color) = _command("feature-style-label-color", (color: color)) +#let feature-text-label-color-at(position, color) = _command("feature-text-label-color-at", (position: position, color: color)) +#let feature-style-label-color-at(position, color) = _command("feature-style-label-color-at", (position: position, color: color)) +#let tcoffee-scores(source) = _command("tcoffee-scores", (source: source)) +#let sequence-logo-track(position: "top", colorset: none) = _command("sequence-logo-track", (position: position, colorset: colorset)) +#let no-sequence-logo-track() = _command("no-sequence-logo-track", (:)) +#let frequency-correction() = _command("frequency-correction", (:)) +#let no-frequency-correction() = _command("no-frequency-correction", (:)) +#let subfamily(sequences) = _command("subfamily", (sequences: sequences)) +#let subfamily-logo-track(position: "top", colorset: none) = _command("subfamily-logo-track", (position: position, colorset: colorset)) +#let no-subfamily-logo-track() = _command("no-subfamily-logo-track", (:)) +#let sequence-logo-name(name) = _command("sequence-logo-name", (name: name)) +#let subfamily-logo-name(name, negative-name: none) = _command("subfamily-logo-name", (name: name, negative-name: negative-name)) +#let logo-scale(position: "leftright", color: "Black") = _command("logo-scale", (position: position, color: color)) +#let no-logo-scale() = _command("no-logo-scale", (:)) +#let logo-stretch(value) = _command("logo-stretch", (value: value)) +#let negative-logo-values() = _command("negative-logo-values", (:)) +#let no-negative-logo-values() = _command("no-negative-logo-values", (:)) +#let relevance-threshold(value) = _command("relevance-threshold", (value: value)) +#let relevance-marker(char: "*", color: "Black") = _command("relevance-marker", (char: char, color: color)) +#let no-relevance-marker() = _command("no-relevance-marker", (:)) +#let logo-color(residues, color) = _command("logo-color", (residues: residues, color: color)) +#let clear-logo-colors(default: "Black") = _command("clear-logo-colors", (default: default)) +#let legend-track(color: "Black") = _command("legend-track", (color: color)) +#let no-legend-track() = _command("no-legend-track", (:)) +#let legend-color(color) = _command("legend-color", (color: color)) +#let legend-offset(dx, dy) = _command("legend-offset", (dx: dx, dy: dy)) +#let color-swatch(color) = box(width: 10pt, height: 10pt, fill: resolve-color(color), stroke: none)[] +#let show-structure-types(format, types) = _command("show-structure-types", (format: format, types: types)) +#let hide-structure-types(format, types) = _command("hide-structure-types", (format: format, types: types)) +#let structure-appearance(format, structure-type, position, style, text) = _command("structure-appearance", (format: format, structure-type: structure-type, position: position, style: style, text: text)) +#let use-first-dssp-column() = _command("use-first-dssp-column", (:)) +#let use-second-dssp-column() = _command("use-second-dssp-column", (:)) +#let stride-track(sequence, source) = _command("stride-track", (sequence: sequence, source: source)) +#let dssp-track(sequence, source) = _command("dssp-track", (sequence: sequence, source: source)) +#let hmmtop-track(sequence, source, source-sequence: none) = _command("hmmtop-track", (sequence: sequence, source: source, source-sequence: source-sequence)) +#let phd-topology-track(sequence, source) = _command("phd-topology-track", (sequence: sequence, source: source)) +#let phd-secondary-track(sequence, source) = _command("phd-secondary-track", (sequence: sequence, source: source)) +#let consensus-from-sequence(sequence) = _command("consensus-from-sequence", (sequence: sequence)) +#let consensus-from-all-sequences() = _command("consensus-from-all-sequences", (:)) +#let show-leading-gaps() = _command("show-leading-gaps", (:)) +#let hide-leading-gaps() = _command("hide-leading-gaps", (:)) +#let shift-single-sequence(..args) = { + let positional = args.pos() + let value = if positional.len() > 0 { positional.first() } else { args.named().at("value", default: -1) } + _command("shift-single-sequence", (value: value)) +} +#let keep-single-sequence-gaps() = _command("keep-single-sequence-gaps", (:)) +#let hide-residues() = _command("hide-residues", (:)) +#let show-residues() = _command("show-residues", (:)) +#let bar-graph-stretch(value, position: none) = _command("bar-graph-stretch", (value: value, position: position)) +#let color-scale-stretch(value, position: none) = _command("color-scale-stretch", (value: value, position: position)) +#let alignment(position) = _command("alignment", (position: position)) +#let character-stretch(value) = _command("character-stretch", (value: value)) +#let line-stretch(value) = _command("line-stretch", (value: value)) +#let numbering-width(digits) = _command("numbering-width", (digits: digits)) +#let fingerprint(value) = _command("fingerprint", (value: value)) +#let align-right-labels() = _command("align-right-labels", (:)) +#let align-left-labels() = _command("align-left-labels", (:)) +#let text-family(target, family) = _command("text-family", (target: target, value: family)) +#let text-weight(target, weight) = _command("text-weight", (target: target, value: weight)) +#let text-posture(target, posture) = _command("text-posture", (target: target, value: posture)) +#let text-size(target, size) = _command("text-size", (target: target, value: size)) +#let text-style(target, family, weight, posture, size) = _command("text-style", (target: target, family: family, weight: weight, posture: posture, size: size)) +#let caption(text, position: "bottom") = _command("caption", (text: text, position: position)) +#let short-caption(text) = _command("short-caption", (text: text)) +#let small-separator() = _command("separator-space", (value: 3pt)) +#let medium-separator() = _command("separator-space", (value: 6pt)) +#let large-separator() = _command("separator-space", (value: 12pt)) +#let export-consensus(sequence, filename, format: "chimera") = _command("export-consensus", (sequence: sequence, filename: filename, format: format)) +#let pdb-selection(selection) = pdb-selection-list(selection) +#let no-block-gap() = _command("block-gap", (value: 0pt)) +#let small-block-gap() = _command("block-gap-factor", (value: 1.0)) +#let medium-block-gap() = _command("block-gap-factor", (value: 1.5)) +#let large-block-gap() = _command("block-gap-factor", (value: 2.0)) +#let block-gap(value) = _command("block-gap", (value: value)) +#let flexible-block-gap() = _command("block-space-mode", (fixed: false)) +#let fixed-block-gap() = _command("block-space-mode", (fixed: true)) +#let no-line-gap() = _command("line-gap", (value: 0pt)) +#let small-line-gap() = _command("line-gap", (value: 3pt)) +#let medium-line-gap() = _command("line-gap", (value: 6pt)) +#let large-line-gap() = _command("line-gap", (value: 12pt)) +#let line-gap(value) = _command("line-gap", (value: value)) +#let feature-slot-space(position, value) = _command("feature-slot-space", (position: position, value: value)) + +#let _apply-command(config, command) = { + let kind = command.at("kind") + if kind == "sequence-type" { + config.insert("seq-type", _upper(str(command.at("value")))) + } else if kind == "scoring-mode" { + config.at("shading").insert("mode", command.at("mode")) + config.at("shading").insert("option", command.at("option")) + if command.at("mode") == "diverse" or command.at("mode") == "singleseq" { + let reference = command.at("option", default: none) + config.at("shading").insert("reference", if reference == none { 1 } else { reference }) + } else if command.at("mode") == "T-Coffee" and command.at("option") != none { + config.at("tcoffee").insert("source", command.at("option")) + config.at("tcoffee").insert("scores", read-tcoffee(command.at("option"))) + } + } else if kind == "color-scheme" { + config.at("shading").insert("scheme", command.at("name")) + _apply-shading-colors(config, command.at("name")) + } else if kind == "define-color-scheme" { + config.at("shading-schemes").insert(command.at("name"), _style-snapshot(config)) + } else if kind == "tcoffee-scores" { + config.at("tcoffee").insert("source", command.at("source")) + config.at("tcoffee").insert("scores", read-tcoffee(command.at("source"))) + } else if kind == "sequence-logo-track" { + config.at("sequence-logo").insert("show", true) + config.at("sequence-logo").insert("position", command.at("position")) + config.at("sequence-logo").insert("colorset", command.at("colorset")) + } else if kind == "no-sequence-logo-track" { + config.at("sequence-logo").insert("show", false) + } else if kind == "frequency-correction" { + config.insert("frequency-correction", true) + } else if kind == "no-frequency-correction" { + config.insert("frequency-correction", false) + } else if kind == "subfamily" { + config.insert("subfamily", command.at("sequences")) + } else if kind == "subfamily-logo-track" { + config.at("subfamily-logo").insert("show", true) + config.at("subfamily-logo").insert("position", command.at("position")) + config.at("subfamily-logo").insert("colorset", command.at("colorset")) + } else if kind == "no-subfamily-logo-track" { + config.at("subfamily-logo").insert("show", false) + } else if kind == "sequence-logo-name" { + config.at("sequence-logo").insert("name", command.at("name")) + } else if kind == "subfamily-logo-name" { + config.at("subfamily-logo").insert("name", command.at("name")) + if command.at("negative-name") != none { + config.at("subfamily-logo").insert("negative-name", command.at("negative-name")) + } + } else if kind == "logo-scale" { + config.at("logo-scale").insert("show", true) + config.at("logo-scale").insert("position", command.at("position")) + config.at("logo-scale").insert("color", command.at("color")) + } else if kind == "no-logo-scale" { + config.at("logo-scale").insert("show", false) + } else if kind == "logo-stretch" { + config.at("sequence-logo").insert("stretch", command.at("value")) + } else if kind == "negative-logo-values" { + config.at("subfamily-logo").insert("show-negatives", true) + } else if kind == "no-negative-logo-values" { + config.at("subfamily-logo").insert("show-negatives", false) + } else if kind == "relevance-threshold" { + config.at("relevance").insert("threshold", command.at("value")) + } else if kind == "relevance-marker" { + config.at("relevance").insert("show", true) + config.at("relevance").insert("char", command.at("char")) + config.at("relevance").insert("color", command.at("color")) + } else if kind == "no-relevance-marker" { + config.at("relevance").insert("show", false) + } else if kind == "logo-color" { + for residue in _chars(command.at("residues")) { + config.at("logo-colors").at("map").insert(_upper(residue), command.at("color")) + } + } else if kind == "clear-logo-colors" { + config.at("logo-colors").insert("default", command.at("default")) + config.at("logo-colors").insert("map", (:)) + } else if kind == "legend-track" { + config.at("legend").insert("show", true) + config.at("legend").insert("color", command.at("color")) + } else if kind == "no-legend-track" { + config.at("legend").insert("show", false) + } else if kind == "legend-color" { + config.at("legend").insert("color", command.at("color")) + } else if kind == "legend-offset" { + config.at("legend").insert("dx", command.at("dx")) + config.at("legend").insert("dy", command.at("dy")) + } else if kind == "show-structure-types" { + config.at("structure-show").insert(command.at("format"), _type-list(command.at("types"))) + } else if kind == "hide-structure-types" { + _hide-structure-types(config, command.at("format"), command.at("types")) + } else if kind == "structure-appearance" { + config.at("structure-appearance").insert(command.at("format") + ":" + command.at("structure-type"), ("position": command.at("position"), "style": command.at("style"), "text": command.at("text"))) + } else if kind == "use-first-dssp-column" { + config.insert("dssp-second-column", false) + } else if kind == "use-second-dssp-column" { + config.insert("dssp-second-column", true) + } else if kind == "stride-track" { + config.at("structure-data").push(("kind": "STRIDE", "sequence": command.at("sequence"), "data": read-stride(command.at("source")))) + } else if kind == "dssp-track" { + config.at("structure-data").push(("kind": "DSSP", "sequence": command.at("sequence"), "data": read-dssp(command.at("source"), use-second-column: config.at("dssp-second-column")))) + } else if kind == "hmmtop-track" { + config.at("structure-data").push(("kind": "HMMTOP", "sequence": command.at("sequence"), "data": read-hmmtop(command.at("source"), sequence: command.at("source-sequence", default: none)))) + } else if kind == "phd-topology-track" { + config.at("structure-data").push(("kind": "PHDtopo", "sequence": command.at("sequence"), "data": read-phd-topology(command.at("source")))) + } else if kind == "phd-secondary-track" { + config.at("structure-data").push(("kind": "PHDsec", "sequence": command.at("sequence"), "data": read-phd-secondary(command.at("source")))) + } else if kind == "threshold" { + config.insert("threshold", command.at("value")) + } else if kind == "shade-all-residues" { + config.insert("threshold", 0) + } else if kind == "all-match-threshold" { + config.insert("allmatch-threshold", command.at("value")) + } else if kind == "disable-all-match-threshold" { + config.insert("allmatch-threshold", 101) + } else if kind == "hide-all-match-positions" { + config.insert("hide-allmatch-positions", true) + } else if kind == "show-all-match-positions" { + config.insert("hide-allmatch-positions", false) + } else if kind == "weight-table" { + let name = str(command.at("name")) + config.insert("weight-table", name) + if name == "PAM250" { + config.insert("gap-penalty", -8) + } else if name == "PAM100" { + config.insert("gap-penalty", -9) + } else { + config.insert("gap-penalty", 0) + } + } else if kind == "set-weight" { + let a = _upper(str(command.at("residue-a"))) + let b = _upper(str(command.at("residue-b"))) + config.at("custom-weights").insert(a + ":" + b, command.at("value")) + config.at("custom-weights").insert(b + ":" + a, command.at("value")) + } else if kind == "gap-penalty" { + config.insert("gap-penalty", command.at("value")) + } else if kind == "residues-per-line" { + config.insert("residues-per-line", command.at("value")) + } else if kind == "auto-layout" { + config.at("auto-layout").insert("fit", command.at("fit")) + config.at("auto-layout").insert("min", command.at("min")) + config.at("auto-layout").insert("max", command.at("max")) + if command.at("fit") != none and command.at("fit") != false { + config.insert("residues-per-line", auto) + } + } else if kind == "auto-page" { + config.at("auto-page").insert("enabled", true) + config.at("auto-page").insert("blocks", command.at("blocks")) + config.at("auto-page").insert("repeat-legend", command.at("repeat-legend")) + } else if kind == "numbering-track" { + let pos = command.at("position") + config.at("numbering").insert("show", true) + config.at("numbering").insert("left", pos == "left" or pos == "leftright") + config.at("numbering").insert("right", pos == "right" or pos == "leftright") + if command.at("color") != none { + config.insert("numbering-color", command.at("color")) + } + } else if kind == "no-numbering-track" { + config.at("numbering").insert("show", false) + } else if kind == "names-track" { + config.at("names").insert("show", true) + config.at("names").insert("position", command.at("position")) + if command.at("color") != none { + config.insert("names-color", command.at("color")) + } + } else if kind == "no-names-track" { + config.at("names").insert("show", false) + } else if kind == "sequence-name" { + config.at("sequence-names").insert(str(command.at("sequence")), command.at("name")) + } else if kind == "names-color" { + config.insert("names-color", command.at("color")) + } else if kind == "sequence-name-color" { + for ref in _ref-list(command.at("sequences")) { + config.at("sequence-name-colors").insert(str(ref), command.at("color")) + } + } else if kind == "hide-sequence-name" { + for ref in _ref-list(command.at("sequences")) { + config.at("hidden-names").push(ref) + } + } else if kind == "numbering-color" { + config.insert("numbering-color", command.at("color")) + } else if kind == "sequence-number-color" { + for ref in _ref-list(command.at("sequences")) { + config.at("sequence-number-colors").insert(str(ref), command.at("color")) + } + } else if kind == "hide-sequence-number" { + for ref in _ref-list(command.at("sequences")) { + config.at("hidden-numbers").push(ref) + } + } else if kind == "consensus-track" { + config.at("consensus").insert("show", true) + config.at("consensus").insert("position", command.at("position")) + config.at("consensus").insert("scale", command.at("scale")) + if command.at("name") != none { + config.at("consensus").insert("name", command.at("name")) + } + } else if kind == "no-consensus-track" { + config.at("consensus").insert("show", false) + } else if kind == "consensus-name" { + config.at("consensus").insert("name", command.at("name")) + } else if kind == "language" { + let name = command.at("name") + config.at("consensus").insert("name", if name == "german" { "Konsensus" } else if name == "spanish" { "consenso" } else { "consensus" }) + } else if kind == "consensus-symbols" { + config.at("consensus").insert("symbols", ("none": command.at("none"), "conserved": command.at("conserved"), "allmatch": command.at("allmatch"))) + } else if kind == "consensus-colors" { + config.at("consensus").insert("colors", ( + "none": (fg: command.at("none-fg"), bg: command.at("none-bg")), + "conserved": (fg: command.at("conserved-fg"), bg: command.at("conserved-bg")), + "allmatch": (fg: command.at("allmatch-fg"), bg: command.at("allmatch-bg")), + )) + } else if kind == "ruler-track" { + config.at("ruler").insert("show", true) + config.at("ruler").insert("position", command.at("position")) + config.at("ruler").insert("sequence", command.at("sequence")) + if command.at("steps") != none { + config.at("ruler").insert("steps", command.at("steps")) + } + if command.at("color") != none { + config.at("ruler").insert("color", command.at("color")) + config.at("ruler-colors").insert("top", command.at("color")) + config.at("ruler-colors").insert("bottom", command.at("color")) + } + } else if kind == "no-ruler-track" { + let pos = command.at("position") + if pos == none or pos == config.at("ruler").at("position") { + config.at("ruler").insert("show", false) + } + } else if kind == "ruler-steps" { + let pos = command.at("position") + if pos == none or pos == config.at("ruler").at("position") { + config.at("ruler").insert("steps", command.at("value")) + } + } else if kind == "ruler-color" { + let pos = command.at("position") + if pos == none { + config.at("ruler").insert("color", command.at("color")) + config.at("ruler-colors").insert("top", command.at("color")) + config.at("ruler-colors").insert("bottom", command.at("color")) + } else { + config.at("ruler-colors").insert(pos, command.at("color")) + } + } else if kind == "ruler-name" { + let pos = command.at("position") + if pos == none { + config.at("ruler-names").insert("top", command.at("name")) + config.at("ruler-names").insert("bottom", command.at("name")) + } else { + config.at("ruler-names").insert(pos, command.at("name")) + } + } else if kind == "ruler-name-color" { + let pos = command.at("position") + if pos == none { + config.at("ruler-name-colors").insert("top", command.at("color")) + config.at("ruler-name-colors").insert("bottom", command.at("color")) + } else { + config.at("ruler-name-colors").insert(pos, command.at("color")) + } + } else if kind == "ruler-marker" { + let pos = command.at("position") + let entry = (text: command.at("text"), color: command.at("color")) + if pos == none { + config.at("ruler-labels").at("top").insert(str(command.at("number")), entry) + config.at("ruler-labels").at("bottom").insert(str(command.at("number")), entry) + } else { + config.at("ruler-labels").at(pos).insert(str(command.at("number")), entry) + } + } else if kind == "ruler-space" { + let pos = command.at("position") + if pos == none { + config.at("ruler-spacing").insert("top", command.at("value")) + config.at("ruler-spacing").insert("bottom", command.at("value")) + } else { + config.at("ruler-spacing").insert(pos, command.at("value")) + } + } else if kind == "rotate-ruler" { + let pos = command.at("position") + if pos == none or pos == "n" { + config.at("ruler-rotation").insert("top", true) + config.at("ruler-rotation").insert("bottom", true) + } else { + config.at("ruler-rotation").insert(pos, true) + } + } else if kind == "unrotate-ruler" { + let pos = command.at("position") + if pos == none or pos == "n" { + config.at("ruler-rotation").insert("top", false) + config.at("ruler-rotation").insert("bottom", false) + } else { + config.at("ruler-rotation").insert(pos, false) + } + } else if kind == "start-number" { + config.at("start-numbers").insert(str(command.at("sequence")), command.at("start")) + if command.at("selection") != none { + config.at("sequence-windows").push((kind: "sequence-window", sequence: command.at("sequence"), selection: command.at("selection"), start: none)) + } + } else if kind == "allow-zero-numbering" { + config.insert("allow-zero", true) + } else if kind == "disallow-zero-numbering" { + config.insert("allow-zero", false) + } else if kind == "sequence-length" { + config.at("sequence-lengths").insert(str(command.at("sequence")), command.at("length")) + } else if kind == "sequence-window" { + if command.at("start") != none { + config.at("start-numbers").insert(str(command.at("sequence")), command.at("start")) + } + config.at("sequence-windows").push(command) + } else if kind == "region-highlight" { + config.at("shade-regions").push(command) + } else if kind == "region-tint" { + config.at("tint-regions").push(command) + } else if kind == "tint-default" { + config.insert("tint-default", command.at("effect")) + } else if kind == "region-lower" { + config.at("lower-regions").push(command) + } else if kind == "region-emphasis" { + config.at("emph-regions").push(command) + } else if kind == "emphasis-default" { + config.insert("emph-default", command.at("style")) + } else if kind == "frame-block" { + config.at("frame-regions").push(command) + } else if kind == "hide-sequence" { + for ref in _ref-list(command.at("sequence")) { + config.at("hidden").push(ref) + } + } else if kind == "hide-all-sequences" { + config.insert("hide-seqs", true) + } else if kind == "show-all-sequences" { + config.insert("hide-seqs", false) + } else if kind == "remove-sequence" { + for ref in _ref-list(command.at("sequence")) { + config.at("killed").push(ref) + } + } else if kind == "no-shade" { + for ref in _ref-list(command.at("sequences")) { + config.at("no-shade").push(ref) + } + } else if kind == "separation-line" { + for ref in _ref-list(command.at("sequence")) { + config.at("separation-lines").push(ref) + } + } else if kind == "sequence-order" { + config.insert("order", _ref-list(command.at("order"))) + } else if kind == "feature" { + config.at("features").push(command) + } else if kind == "feature-rule" { + config.insert("feature-rule", command.at("thickness")) + } else if kind == "codon" { + let residue = _upper(str(command.at("residue"))) + let choices = str(command.at("triplets")).split(",").map(item => item.trim()).filter(item => item != "") + if choices.len() > 0 { + config.at("genetic-code").insert(residue, choices.last()) + } + } else if kind == "genetic-code" { + let name = str(command.at("name")) + config.insert("genetic-code", _standard-genetic-code + if name == "ciliate" { (Q: "YAR") } else { (:) }) + } else if kind == "backtranslation-label" { + config.at("backtranslation").insert("label-style", command.at("style")) + config.at("backtranslation").insert("label-size", command.at("size")) + } else if kind == "backtranslation-text" { + config.at("backtranslation").insert("text-style", command.at("style")) + config.at("backtranslation").insert("text-size", command.at("size")) + } else if kind == "feature-text-label" { + config.at("feature-text-names").insert(command.at("position"), command.at("name")) + } else if kind == "feature-style-label" { + config.at("feature-style-names").insert(command.at("position"), command.at("name")) + } else if kind == "hide-feature-text-label" { + config.at("feature-text-names").insert(command.at("position"), "") + } else if kind == "hide-feature-style-label" { + config.at("feature-style-names").insert(command.at("position"), "") + } else if kind == "hide-feature-text-labels" { + config.insert("feature-text-names", (:)) + } else if kind == "hide-feature-style-labels" { + config.insert("feature-style-names", (:)) + } else if kind == "feature-text-label-color" { + config.at("feature-text-name-colors").insert("default", command.at("color")) + } else if kind == "feature-style-label-color" { + config.at("feature-style-name-colors").insert("default", command.at("color")) + } else if kind == "feature-text-label-color-at" { + config.at("feature-text-name-colors").insert(command.at("position"), command.at("color")) + } else if kind == "feature-style-label-color-at" { + config.at("feature-style-name-colors").insert(command.at("position"), command.at("color")) + } else if kind == "consensus-from-sequence" { + config.at("consensus").insert("source", command.at("sequence")) + } else if kind == "consensus-from-all-sequences" { + config.at("consensus").insert("source", "all") + } else if kind == "show-leading-gaps" { + config.insert("show-leading-gaps", true) + } else if kind == "hide-leading-gaps" { + config.insert("show-leading-gaps", false) + } else if kind == "shift-single-sequence" { + config.insert("single-seq-shift", command.at("value")) + } else if kind == "keep-single-sequence-gaps" { + config.insert("keep-single-seq-gaps", true) + } else if kind == "hide-residues" { + config.insert("hide-residues", true) + } else if kind == "show-residues" { + config.insert("hide-residues", false) + } else if kind == "gap-char" { + config.at("gaps").insert("char", command.at("symbol")) + } else if kind == "gap-rule" { + config.at("gaps").insert("rule-thickness", command.at("thickness")) + } else if kind == "gap-colors" { + config.at("gaps").insert("fg", command.at("foreground")) + config.at("gaps").insert("bg", command.at("background")) + } else if kind == "stop-char" { + config.insert("stop-char", command.at("symbol")) + } else if kind == "peptide-groups" { + config.insert("pep-groups", _group-list(command.at("groups"))) + } else if kind == "dna-groups" { + config.insert("dna-groups", _group-list(command.at("groups"))) + } else if kind == "peptide-similarities" { + config.at("pep-sims").insert(_upper(str(command.at("residue"))), _upper(str(command.at("similars")))) + } else if kind == "dna-similarities" { + config.at("dna-sims").insert(_upper(str(command.at("residue"))), _upper(str(command.at("similars")))) + } else if kind == "residue-style" { + config.at("residue-style").insert(command.at("target"), _style-record(command.at("fg"), command.at("bg"), command.at("case"), command.at("style"))) + } else if kind == "cell-style" { + config.at("cell-styles").push(command.at("callback")) + } else if kind == "clear-functional-groups" { + config.at("functional-groups").insert("custom", ()) + config.insert("functional-default", "custom") + } else if kind == "functional-group" { + let groups = config.at("functional-groups").at("custom", default: ()) + groups.push(_func-style-record(command.at("name"), command.at("residues"), command.at("fg"), command.at("bg"), command.at("case"), command.at("style"))) + config.at("functional-groups").insert("custom", groups) + config.insert("functional-default", "custom") + } else if kind == "functional-style" { + config.at("functional-style-overrides").insert(_upper(str(command.at("residue"))), _style-record(command.at("fg"), command.at("bg"), command.at("case"), command.at("style"))) + } else if kind == "bar-graph-stretch" { + let key = if command.at("position") == none { "default" } else { command.at("position") } + config.at("bar-graph-stretch").insert(key, command.at("value")) + } else if kind == "color-scale-stretch" { + let key = if command.at("position") == none { "default" } else { command.at("position") } + config.at("color-scale-stretch").insert(key, command.at("value")) + } else if kind == "alignment" { + config.insert("alignment", command.at("position")) + } else if kind == "character-stretch" { + config.insert("char-stretch", command.at("value")) + } else if kind == "line-stretch" { + config.insert("line-gap", config.at("font-size") * command.at("value")) + } else if kind == "numbering-width" { + config.insert("numbering-width-digits", command.at("digits")) + } else if kind == "fingerprint" { + config.insert("residues-per-line", command.at("value")) + config.at("names").insert("show", true) + config.at("names").insert("position", "left") + config.at("numbering").insert("show", false) + config.at("ruler").insert("steps", 100) + config.at("residue-style").insert("nomatch", _style-record("Black", "Gray10", "upper", "normal")) + } else if kind == "align-right-labels" { + config.insert("align-right-labels", true) + } else if kind == "align-left-labels" { + config.insert("align-right-labels", false) + } else if kind == "text-family" { + _set-text-style(config, command.at("target"), "family", command.at("value")) + } else if kind == "text-weight" { + _set-text-style(config, command.at("target"), "weight", command.at("value")) + } else if kind == "text-posture" { + _set-text-style(config, command.at("target"), "style", command.at("value")) + } else if kind == "text-size" { + _set-text-style(config, command.at("target"), "size", command.at("value")) + } else if kind == "text-style" { + _set-text-style(config, command.at("target"), "family", command.at("family")) + _set-text-style(config, command.at("target"), "weight", command.at("weight")) + _set-text-style(config, command.at("target"), "style", command.at("posture")) + _set-text-style(config, command.at("target"), "size", command.at("size")) + } else if kind == "caption" { + config.at("captions").insert(command.at("position"), command.at("text")) + } else if kind == "short-caption" { + config.at("captions").insert("short", command.at("text")) + } else if kind == "separator-space" { + config.insert("separation-space", command.at("value")) + } else if kind == "export-consensus" { + config.insert("exported-consensus", command) + } else if kind == "block-gap" { + config.insert("block-gap", command.at("value")) + } else if kind == "block-gap-factor" { + config.insert("block-gap", config.at("font-size") * command.at("value")) + } else if kind == "block-space-mode" { + config.insert("fixed-block-space", command.at("fixed")) + } else if kind == "line-gap" { + config.insert("line-gap", command.at("value")) + } else if kind == "feature-slot-space" { + config.at("feature-slot-spacing").insert(command.at("position"), command.at("value")) + } + config +} diff --git a/packages/preview/typshade/0.1.3/internal/engine/layout.typ b/packages/preview/typshade/0.1.3/internal/engine/layout.typ new file mode 100644 index 0000000000..f0039ed707 --- /dev/null +++ b/packages/preview/typshade/0.1.3/internal/engine/layout.typ @@ -0,0 +1,394 @@ +// Copyright (C) 2026 Eito Yoneyama +// SPDX-License-Identifier: GPL-2.0 + +#import "../model/pdb.typ": _pdb-selection-positions +#import "../model/parser.typ": _chars, _lower, _upper + +#let _motif-pattern(selection) = { + let text = str(selection).trim() + if text == "" or text == "all" or text.contains("..") or text.contains(":") or text.matches(regex("^\\d+(?:\\s*,\\s*\\d+)*$")).len() > 0 { + return none + } + let pattern = () + let idx = 0 + while idx < text.len() { + let ch = text.slice(idx, idx + 1) + if ch == "[" { + let rest = text.slice(idx + 1) + let close = rest.position("]") + if close == none { + return none + } + pattern.push(_upper(rest.slice(0, close))) + idx += close + 2 + } else if ch == "X" or ch == "x" { + pattern.push(none) + idx += 1 + } else if ch.matches(regex("[A-Za-z]")).len() > 0 { + pattern.push(_upper(ch)) + idx += 1 + } else { + return none + } + } + pattern +} + +#let _motif-columns(seq, selection) = { + let pattern = _motif-pattern(selection) + if pattern == none { + return none + } + let residues = () + let columns = () + for (idx, ch) in _chars(seq.at("aligned")).enumerate() { + if ch == "." or ch == "-" { + continue + } + residues.push(_upper(ch)) + columns.push(idx) + } + let out = () + if pattern.len() == 0 or residues.len() < pattern.len() { + return out + } + for start in range(0, residues.len() - pattern.len() + 1) { + let matched = true + for offset in range(0, pattern.len()) { + let allowed = pattern.at(offset) + if allowed != none and not allowed.contains(residues.at(start + offset)) { + matched = false + } + } + if matched { + for offset in range(0, pattern.len()) { + out.push(columns.at(start + offset)) + } + } + } + out +} + +#let _selection-fail(selection, reason) = { + assert(false, message: "typshade: invalid selection `" + str(selection) + "`: " + reason) +} + +#let _is-gap(char) = char == "." or char == "-" + +#let _all-columns(seq) = { + let out = () + for idx in range(0, seq.at("aligned").len()) { + out.push(idx) + } + out +} + +#let _set-key(item) = str(item) + +#let _contains-column(items, column) = { + let key = _set-key(column) + for item in items { + if _set-key(item) == key { + return true + } + } + false +} + +#let _union-columns(groups) = { + let out = () + let seen = (:) + for group in groups { + for column in group { + let key = _set-key(column) + if not seen.keys().contains(key) { + seen.insert(key, true) + out.push(column) + } + } + } + out.sorted() +} + +#let _intersection-columns(groups) = { + if groups.len() == 0 { + return () + } + let out = () + for column in groups.first() { + let present = true + for group in groups.slice(1) { + if not _contains-column(group, column) { + present = false + } + } + if present and not _contains-column(out, column) { + out.push(column) + } + } + out.sorted() +} + +#let _difference-columns(base, remove) = base.filter(column => not _contains-column(remove, column)) + +#let _selection-columns-from-positions(seq, positions) = { + let wanted = if type(positions) == array { positions } else { (positions,) } + let out = () + for (idx, mapped) in seq.at("positions").enumerate() { + if mapped != none and wanted.contains(mapped) { + out.push(idx) + } + } + out +} + +#let _selection-columns-from-range(seq, start, stop) = { + let out = () + let low = calc.min(start, stop) + let high = calc.max(start, stop) + for (idx, pos) in seq.at("positions").enumerate() { + if pos != none and pos >= low and pos <= high { + out.push(idx) + } + } + out +} + +#let _column-residues(alignment, column) = { + let residues = () + for sequence in alignment.at("sequences") { + let ch = _upper(sequence.at("aligned").slice(column, column + 1)) + if not _is-gap(ch) { + residues.push(ch) + } + } + residues +} + +#let _column-metric(alignment, column, metric) = { + let name = _lower(str(metric)) + let count = alignment.at("sequences").len() + let residues = _column-residues(alignment, column) + let covered = residues.len() + if name == "coverage" { + if count == 0 { 0.0 } else { covered * 100.0 / count } + } else if name == "gap-fraction" or name == "gaps" { + if count == 0 { 0.0 } else { (count - covered) * 100.0 / count } + } else if name == "entropy" { + if covered == 0 { + 0.0 + } else { + let counts = (:) + for residue in residues { + counts.insert(residue, counts.at(residue, default: 0) + 1) + } + let total = 0.0 + for value in counts.values() { + let p = value / covered + total -= p * calc.log(p) / calc.log(2) + } + total + } + } else if name == "conservation" or name == "identity" { + if covered == 0 { + 0.0 + } else { + let counts = (:) + for residue in residues { + counts.insert(residue, counts.at(residue, default: 0) + 1) + } + let max-count = 0 + for value in counts.values() { + if value > max-count { + max-count = value + } + } + max-count * 100.0 / covered + } + } else { + _selection-fail((kind: "typshade-selection", op: "metric", metric: metric), "unknown metric `" + str(metric) + "`") + } +} + +#let _metric-passes(value, spec) = { + if spec.at("above", default: none) != none and not (value > spec.at("above")) { + return false + } + if spec.at("below", default: none) != none and not (value < spec.at("below")) { + return false + } + if spec.at("at-least", default: spec.at("min", default: none)) != none and value < spec.at("at-least", default: spec.at("min", default: none)) { + return false + } + if spec.at("at-most", default: spec.at("max", default: none)) != none and value > spec.at("at-most", default: spec.at("max", default: none)) { + return false + } + if spec.at("equals", default: none) != none and value != spec.at("equals") { + return false + } + true +} + +#let _selection-columns-from-metric(seq, selection, alignment, resolve) = { + assert(alignment != none, message: "typshade: metric selections require alignment context") + let base = resolve(selection.at("selection", default: "all")) + let out = () + for column in base { + let value = _column-metric(alignment, column, selection.at("metric", default: selection.at("name", default: "conservation"))) + if _metric-passes(value, selection) { + out.push(column) + } + } + out +} + +#let _pad-selection-columns(seq, columns, before, after) = { + if columns.len() == 0 { + return () + } + let first = none + let last = none + for column in columns { + let pos = seq.at("positions").at(column) + if pos != none { + if first == none or pos < first { + first = pos + } + if last == none or pos > last { + last = pos + } + } + } + if first == none or last == none { + return columns + } + _selection-columns-from-range(seq, calc.max(1, first - before), last + after) +} + +#let _selection-dsl-columns(seq, selection, alignment: none, resolve: none) = { + let op = selection.at("op", default: "or") + if op == "all" { + return _all-columns(seq) + } + if op == "range" { + let range-value = selection.at("range", default: none) + if range-value != none { + return resolve(range-value) + } + return _selection-columns-from-range(seq, int(selection.at("start")), int(selection.at("stop", default: selection.at("start")))) + } + if op == "positions" { + return _selection-columns-from-positions(seq, selection.at("positions")) + } + if op == "motif" { + let columns = _motif-columns(seq, selection.at("pattern")) + return if columns == none { () } else { columns } + } + if op == "metric" { + return _selection-columns-from-metric(seq, selection, alignment, resolve) + } + if op == "not" { + return _difference-columns(_all-columns(seq), resolve(selection.at("selection"))) + } + if op == "pad" { + let before = int(selection.at("before", default: selection.at("padding", default: 0))) + let after = int(selection.at("after", default: before)) + return _pad-selection-columns(seq, resolve(selection.at("selection")), before, after) + } + let items = selection.at("items", default: ()) + let groups = items.map(item => resolve(item)) + let columns = if op == "and" { + _intersection-columns(groups) + } else if op == "or" or op == "select" { + _union-columns(groups) + } else { + _selection-fail(selection, "unknown selection operation `" + str(op) + "`") + } + let padding = int(selection.at("padding", default: 0)) + if padding != 0 { + _pad-selection-columns(seq, columns, padding, padding) + } else { + columns + } +} + +#let _selection-columns(seq, selection, alignment: none) = { + if selection == none { + return () + } + if type(selection) == dictionary and selection.at("kind", default: none) == "typshade-selection" { + return _selection-dsl-columns(seq, selection, alignment: alignment, resolve: item => _selection-columns(seq, item, alignment: alignment)) + } + let pdb-positions = _pdb-selection-positions(selection) + if pdb-positions != none { + let values = () + for (idx, mapped) in seq.at("positions").enumerate() { + if mapped != none and pdb-positions.contains(mapped) { + values.push(idx) + } + } + return values + } + let motif-columns = _motif-columns(seq, selection) + if motif-columns != none { + return motif-columns + } + let text = str(selection).trim() + if text.trim() == "all" { + return _all-columns(seq) + } + if text.contains(":") { + _selection-fail(selection, "expected a valid PDB selection such as point[1]:source,1[CA]") + } + if text.matches(regex("[A-Za-z\\[]")).len() > 0 { + _selection-fail(selection, "expected a residue range/list or a valid motif pattern") + } + let values = () + for part in text.split(",") { + let trimmed = part.trim() + if trimmed == "" { + continue + } + if trimmed.contains("..") { + let bounds = trimmed.split("..") + assert( + bounds.len() == 2 and bounds.first().matches(regex("^\\d+$")).len() > 0 and bounds.last().matches(regex("^\\d+$")).len() > 0, + message: "typshade: invalid selection `" + str(selection) + "`: ranges must look like 1..10", + ) + values += _selection-columns-from-range(seq, int(bounds.first()), int(bounds.last())) + } else { + assert( + trimmed.matches(regex("^\\d+$")).len() > 0, + message: "typshade: invalid selection `" + str(selection) + "`: entries must be residue numbers, ranges, motifs, or all", + ) + values += _selection-columns-from-positions(seq, int(trimmed)) + } + } + values +} + +#let _sorted-unique(items) = { + let seen = (:) + let out = () + for item in items { + let key = str(item) + if not seen.keys().contains(key) { + seen.insert(key, true) + out.push(item) + } + } + out.sorted() +} + +#let _empty-cell() = (char: "", fg: "Black", bg: none, emph: false, frame: none) + +#let _ordinal-label(index) = { + let letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + if index <= letters.len() { + letters.slice(index - 1, index) + } else { + str(index) + } +} + +#let _selection-string(range) = str(range.at(0)) + ".." + str(range.at(1)) diff --git a/packages/preview/typshade/0.1.3/internal/interface/analysis.typ b/packages/preview/typshade/0.1.3/internal/interface/analysis.typ new file mode 100644 index 0000000000..6198bff61b --- /dev/null +++ b/packages/preview/typshade/0.1.3/internal/interface/analysis.typ @@ -0,0 +1,185 @@ +// Copyright (C) 2026 Eito Yoneyama +// SPDX-License-Identifier: GPL-2.0 + +#import "../engine/layout.typ" as _layout +#import "../model/logo.typ" as _logo +#import "../model/palette.typ" as _palette +#import "../model/parser.typ" as _parser + +#let _upper(text) = { + let lower = "abcdefghijklmnopqrstuvwxyz" + let upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + let out = "" + for ch in str(text).clusters() { + let idx = lower.position(ch) + out += if idx == none { ch } else { upper.slice(idx, idx + 1) } + } + out +} + +#let _is-gap(value) = { + let ch = str(value) + ch == "" or ch == "." or ch == "-" +} + +#let _sequence-index(alignment, sequence) = _logo._resolve-sequence(alignment, sequence) + +#let _selected-columns(alignment, reference, selection) = { + if selection == none or selection == "all" { + return range(0, alignment.at("columns")) + } + let ref-index = _sequence-index(alignment, reference) + _layout._selection-columns(alignment.at("sequences").at(ref-index), selection, alignment: alignment) +} + +#let _similar-residue(a, b, seq-type, similarities: none, groups: none) = { + let left = _upper(a) + let right = _upper(b) + if left == right { + return true + } + let resolved-sims = if similarities != none { + similarities + } else if seq-type == "N" { + _palette._dna-sims + } else { + _palette._pep-sims + } + let left-sims = resolved-sims.at(left, default: "") + let right-sims = resolved-sims.at(right, default: "") + if str(left-sims).contains(right) or str(right-sims).contains(left) { + return true + } + let resolved-groups = if groups != none { + groups + } else if seq-type == "N" { + _palette._dna-groups + } else { + _palette._pep-groups + } + for group in resolved-groups { + let text = _upper(group) + if text.contains(left) and text.contains(right) { + return true + } + } + false +} + +#let _percent-score( + alignment, + sequence-a, + sequence-b, + kind, + selection: "all", + reference: auto, + seq-type: auto, + similarities: none, + groups: none, +) = { + let left-index = _sequence-index(alignment, sequence-a) + let right-index = _sequence-index(alignment, sequence-b) + let left = alignment.at("sequences").at(left-index) + let right = alignment.at("sequences").at(right-index) + let resolved-reference = if reference == auto { sequence-a } else { reference } + let resolved-type = if seq-type == auto { alignment.at("seq-type") } else { _upper(seq-type) } + let total = 0 + let hits = 0 + for col in _selected-columns(alignment, resolved-reference, selection) { + let a = left.at("aligned").slice(col, col + 1) + let b = right.at("aligned").slice(col, col + 1) + if not _is-gap(a) and not _is-gap(b) { + total += 1 + if _upper(a) == _upper(b) { + hits += 1 + } else if kind == "similarity" and _similar-residue(a, b, resolved-type, similarities: similarities, groups: groups) { + hits += 1 + } + } + } + if total == 0 { + 0.0 + } else { + calc.round(hits / total * 1000) / 10 + } +} + +#let percent-identity( + source, + sequence-a, + sequence-b, + format: auto, + selection: "all", + reference: auto, + seq-type: auto, +) = { + let alignment = _parser.read-alignment(source, format: format) + _percent-score(alignment, sequence-a, sequence-b, "identity", selection: selection, reference: reference, seq-type: seq-type) +} + +#let percent-similarity( + source, + sequence-a, + sequence-b, + format: auto, + selection: "all", + reference: auto, + seq-type: auto, + similarities: none, + groups: none, +) = { + let alignment = _parser.read-alignment(source, format: format) + _percent-score( + alignment, + sequence-a, + sequence-b, + "similarity", + selection: selection, + reference: reference, + seq-type: seq-type, + similarities: similarities, + groups: groups, + ) +} + +#let similarity-table( + source, + format: auto, + selection: "all", + reference: auto, + seq-type: auto, + similarities: none, + groups: none, +) = { + let alignment = _parser.read-alignment(source, format: format) + let sequences = alignment.at("sequences") + let columns = (auto,) + let rows = ([],) + for seq in sequences { + columns.push(auto) + rows.push([#seq.at("name")]) + } + for (row-index, row-seq) in sequences.enumerate() { + rows.push([#row-seq.at("name")]) + for (col-index, col-seq) in sequences.enumerate() { + if row-index == col-index { + rows.push([-]) + } else { + let kind = if col-index > row-index { "similarity" } else { "identity" } + let value = _percent-score( + alignment, + row-index + 1, + col-index + 1, + kind, + selection: selection, + reference: if reference == auto { row-index + 1 } else { reference }, + seq-type: seq-type, + similarities: similarities, + groups: groups, + ) + rows.push([#str(value)]) + } + } + } + table(columns: columns, inset: (x: 5pt, y: 3pt), ..rows) +} diff --git a/packages/preview/typshade/0.1.3/internal/interface/annotations.typ b/packages/preview/typshade/0.1.3/internal/interface/annotations.typ new file mode 100644 index 0000000000..8333bdaa5a --- /dev/null +++ b/packages/preview/typshade/0.1.3/internal/interface/annotations.typ @@ -0,0 +1,53 @@ +// Copyright (C) 2026 Eito Yoneyama +// SPDX-License-Identifier: GPL-2.0 + +#import "../engine/config.typ" as _config + +#let pdb-point(source, residue, distance: 1, atom: "side") = ( + kind: "pdb-selection", + shape: "point", + source: source, + distance: distance, + anchors: ((residue: residue, atom: atom),), +) + +#let pdb-line(source, residue-a, residue-b, distance: 1, atom-a: "side", atom-b: "side") = ( + kind: "pdb-selection", + shape: "line", + source: source, + distance: distance, + anchors: ((residue: residue-a, atom: atom-a), (residue: residue-b, atom: atom-b)), +) + +#let pdb-plane(source, residue-a, residue-b, residue-c, distance: 1, atom-a: "side", atom-b: "side", atom-c: "side") = ( + kind: "pdb-selection", + shape: "plane", + source: source, + distance: distance, + anchors: ((residue: residue-a, atom: atom-a), (residue: residue-b, atom: atom-b), (residue: residue-c, atom: atom-c)), +) + +#let highlight(sequence, selection, fg: "White", bg: "RoyalBlue", all: false) = _config.region-highlight(sequence, selection, fg, bg, apply-to-all: all) +#let tint(sequence, selection, intensity: "medium") = _config.region-tint(sequence, selection, intensity: intensity) +#let emphasize(sequence, selection, style: "italic") = _config.region-emphasis(sequence, selection, style: style) + +#let mark(position, sequence, selection, fill: "Yellow", text: "", style: none) = { + let resolved-style = if style == none { "box[" + str(fill) + "]" } else { style } + _config.feature(position, sequence, selection, style: resolved-style, text: text) +} + +#let motif(sequence, selection, text: "motif", position: "top", fg: "White", bg: "RoyalBlue", fill: "Yellow", all: false) = ( + highlight(sequence, selection, fg: fg, bg: bg, all: all), + mark(position, sequence, selection, fill: fill, text: text), +) + +#let graph(position, sequence, selection, metric, kind: "bar", range: none, options: none, text: "") = { + let style = ( + kind: str(kind), + metric: metric, + min: if range == none { none } else { range.at(0) }, + max: if range == none { none } else { range.at(1) }, + options: if options == none { () } else { options }, + ) + _config.feature(position, sequence, selection, style: style, text: text) +} diff --git a/packages/preview/typshade/0.1.3/internal/interface/controls.typ b/packages/preview/typshade/0.1.3/internal/interface/controls.typ new file mode 100644 index 0000000000..c956dd8f23 --- /dev/null +++ b/packages/preview/typshade/0.1.3/internal/interface/controls.typ @@ -0,0 +1,191 @@ +// Copyright (C) 2026 Eito Yoneyama +// SPDX-License-Identifier: GPL-2.0 + +#import "../engine/config.typ" as _config + +#let sequence-type(value) = _config.sequence-type(value) +#let color-scheme(name) = _config.color-scheme(name) +#let scoring-mode(name, option: none) = _config.scoring-mode(name, option: option) +#let tcoffee-scores(source) = scoring-mode("T-Coffee", option: source) +#let sequence-window(sequence, selection, start: none) = _config.sequence-window(sequence, selection, start: start) +#let residues-per-line(value) = _config.residues-per-line(value) +#let auto-layout(fit: "container", min: 1, max: none) = _config.auto-layout(fit: fit, min: min, max: max) +#let auto-page(blocks: auto, repeat-legend: true) = _config.auto-page(blocks: blocks, repeat-legend: repeat-legend) +#let threshold(value) = _config.threshold(value) +#let shade-all-residues() = _config.shade-all-residues() +#let all-match-threshold(value: 100) = _config.all-match-threshold(value: value) +#let disable-all-match-threshold() = _config.disable-all-match-threshold() +#let hide-all-match-positions() = _config.hide-all-match-positions() +#let show-all-match-positions() = _config.show-all-match-positions() + +#let weight-table(name) = _config.weight-table(name) +#let set-weight(residue-a, residue-b, value) = _config.set-weight(residue-a, residue-b, value) +#let gap-penalty(value) = _config.gap-penalty(value) + +#let residue-style(target, fg, bg, case: "upper", style: "normal") = _config.residue-style(target, fg, bg, case: case, style: style) +#let cell-style(callback) = _config.cell-style(callback) +#let peptide-groups(groups) = _config.peptide-groups(groups) +#let dna-groups(groups) = _config.dna-groups(groups) +#let peptide-similarities(residue, similars) = _config.peptide-similarities(residue, similars) +#let dna-similarities(residue, similars) = _config.dna-similarities(residue, similars) +#let clear-functional-groups() = _config.clear-functional-groups() +#let functional-group(name, residues, fg, bg, case: "upper", style: "normal") = _config.functional-group(name, residues, fg, bg, case: case, style: style) +#let functional-style(residue, fg, bg, case: "upper", style: "normal") = _config.functional-style(residue, fg, bg, case: case, style: style) + +#let names-track(position: "left", color: none) = _config.names-track(position: position, color: color) +#let no-names() = _config.no-names-track() +#let numbering-track(position: "right", color: none) = _config.numbering-track(position: position, color: color) +#let no-numbering() = _config.no-numbering-track() +#let sequence-name(sequence, name) = _config.sequence-name(sequence, name) +#let names-color(color) = _config.names-color(color) +#let sequence-name-color(sequences, color) = _config.sequence-name-color(sequences, color) +#let hide-sequence-name(sequences) = _config.hide-sequence-name(sequences) +#let numbering-color(color) = _config.numbering-color(color) +#let sequence-number-color(sequences, color) = _config.sequence-number-color(sequences, color) +#let hide-sequence-number(sequences) = _config.hide-sequence-number(sequences) + +#let consensus-name(name) = _config.consensus-name(name) +#let consensus-language(name) = _config.language(name) +#let consensus-symbols(none-symbol, conserved-symbol, allmatch-symbol) = _config.consensus-symbols(none-symbol, conserved-symbol, allmatch-symbol) +#let consensus-colors(none-fg: "Black", none-bg: "White", conserved-fg: "Black", conserved-bg: "White", allmatch-fg: "Black", allmatch-bg: "White") = _config.consensus-colors( + none-fg: none-fg, + none-bg: none-bg, + conserved-fg: conserved-fg, + conserved-bg: conserved-bg, + allmatch-fg: allmatch-fg, + allmatch-bg: allmatch-bg, +) +#let consensus-from-sequence(sequence) = _config.consensus-from-sequence(sequence) +#let consensus-from-all-sequences() = _config.consensus-from-all-sequences() + +#let ruler-steps(value, position: none) = _config.ruler-steps(value, position: position) +#let ruler-color(color, position: none) = _config.ruler-color(color, position: position) +#let ruler-name(name, position: none) = _config.ruler-name(name, position: position) +#let ruler-name-color(color, position: none) = _config.ruler-name-color(color, position: position) +#let ruler-space(value, position: none) = _config.ruler-space(value, position: position) +#let rotate-ruler(position: none) = _config.rotate-ruler(position) +#let unrotate-ruler(position: none) = _config.unrotate-ruler(position) + +#let gap-char(symbol) = _config.gap-char(symbol) +#let gap-rule(thickness) = _config.gap-rule(thickness) +#let gap-colors(foreground, background) = _config.gap-colors(foreground, background) +#let stop-char(symbol) = _config.stop-char(symbol) +#let show-leading-gaps() = _config.show-leading-gaps() +#let hide-leading-gaps() = _config.hide-leading-gaps() + +#let start-number(sequence, start, selection: none) = _config.start-number(sequence, start, selection: selection) +#let allow-zero-numbering() = _config.allow-zero-numbering() +#let disallow-zero-numbering() = _config.disallow-zero-numbering() +#let sequence-length(sequence, length) = _config.sequence-length(sequence, length) +#let domain(sequence, selection) = _config.domain(sequence, selection) +#let domain-gap-rule(thickness) = _config.domain-gap-rule(thickness) +#let domain-gap-colors(foreground, background) = _config.domain-gap-colors(foreground, background) + +#let highlight-block(sequence, selection, ..args) = _config.highlight-block(sequence, selection, ..args) +#let region-color-scheme(sequence, selection, scheme) = _config.region-color-scheme(sequence, selection, scheme) +#let lower(sequence, selection) = _config.region-lower(sequence, selection) +#let lower-block(sequence, selection) = _config.lower-block(sequence, selection) +#let emphasis-block(sequence, selection, style: "italic") = _config.emphasis-block(sequence, selection, style: style) +#let tint-block(sequence, selection, intensity: "medium") = _config.tint-block(sequence, selection, intensity: intensity) +#let tint-default(effect) = _config.tint-default(effect) +#let emphasis-default(style) = _config.emphasis-default(style) +#let frame(sequence, selection, color: "Red") = _config.frame-block(sequence, selection, color: color) + +#let hide-sequence(sequence) = _config.hide-sequence(sequence) +#let hide-all-sequences() = _config.hide-all-sequences() +#let show-all-sequences() = _config.show-all-sequences() +#let remove-sequence(sequence) = _config.remove-sequence(sequence) +#let no-shade(sequences) = _config.no-shade(sequences) +#let separation-line(sequence) = _config.separation-line(sequence) +#let sequence-order(order) = _config.sequence-order(order) + +#let feature-rule(thickness) = _config.feature-rule(thickness) +#let codon(residue, triplets) = _config.codon(residue, triplets) +#let genetic-code(name) = _config.genetic-code(name) +#let backtranslation-label(..args) = _config.backtranslation-label(..args) +#let backtranslation-text(..args) = _config.backtranslation-text(..args) +#let feature-text-label(position, name) = _config.feature-text-label(position, name) +#let feature-style-label(position, name) = _config.feature-style-label(position, name) +#let hide-feature-text-label(position) = _config.hide-feature-text-label(position) +#let hide-feature-style-label(position) = _config.hide-feature-style-label(position) +#let hide-feature-text-labels() = _config.hide-feature-text-labels() +#let hide-feature-style-labels() = _config.hide-feature-style-labels() +#let feature-text-label-color(color) = _config.feature-text-label-color(color) +#let feature-style-label-color(color) = _config.feature-style-label-color(color) +#let feature-text-label-color-at(position, color) = _config.feature-text-label-color-at(position, color) +#let feature-style-label-color-at(position, color) = _config.feature-style-label-color-at(position, color) + +#let frequency-correction() = _config.frequency-correction() +#let no-frequency-correction() = _config.no-frequency-correction() +#let subfamily(sequences) = _config.subfamily(sequences) +#let sequence-logo-name(name) = _config.sequence-logo-name(name) +#let subfamily-logo-name(name, negative-name: none) = _config.subfamily-logo-name(name, negative-name: negative-name) +#let logo-scale(position: "leftright", color: "Black") = _config.logo-scale(position: position, color: color) +#let no-logo-scale() = _config.no-logo-scale() +#let logo-stretch(value) = _config.logo-stretch(value) +#let negative-logo-values() = _config.negative-logo-values() +#let no-negative-logo-values() = _config.no-negative-logo-values() +#let relevance-threshold(value) = _config.relevance-threshold(value) +#let relevance-marker(char: "*", color: "Black") = _config.relevance-marker(char: char, color: color) +#let no-relevance-marker() = _config.no-relevance-marker() +#let logo-color(residues, color) = _config.logo-color(residues, color) +#let clear-logo-colors(default: "Black") = _config.clear-logo-colors(default: default) + +#let no-legend() = _config.no-legend-track() +#let legend-color(color) = _config.legend-color(color) +#let legend-offset(dx, dy) = _config.legend-offset(dx, dy) +#let color-swatch(color) = _config.color-swatch(color) + +#let show-structure-types(format, types) = _config.show-structure-types(format, types) +#let hide-structure-types(format, types) = _config.hide-structure-types(format, types) +#let structure-appearance(format, structure-type, position, style, text) = _config.structure-appearance(format, structure-type, position, style, text) +#let use-first-dssp-column() = _config.use-first-dssp-column() +#let use-second-dssp-column() = _config.use-second-dssp-column() +#let stride-track(sequence, source) = _config.stride-track(sequence, source) +#let dssp-track(sequence, source) = _config.dssp-track(sequence, source) +#let hmmtop-track(sequence, source, source-sequence: none) = _config.hmmtop-track(sequence, source, source-sequence: source-sequence) +#let phd-topology-track(sequence, source) = _config.phd-topology-track(sequence, source) +#let phd-secondary-track(sequence, source) = _config.phd-secondary-track(sequence, source) + +#let keep-single-sequence-gaps() = _config.keep-single-sequence-gaps() +#let shift-single-sequence(value: -1) = _config.shift-single-sequence(value) +#let hide-residues() = _config.hide-residues() +#let show-residues() = _config.show-residues() +#let bar-graph-stretch(value, position: none) = _config.bar-graph-stretch(value, position: position) +#let color-scale-stretch(value, position: none) = _config.color-scale-stretch(value, position: position) +#let alignment-position(position) = _config.alignment(position) +#let character-stretch(value) = _config.character-stretch(value) +#let line-stretch(value) = _config.line-stretch(value) +#let numbering-width(digits) = _config.numbering-width(digits) +#let fingerprint(value) = _config.fingerprint(value) +#let align-right-labels() = _config.align-right-labels() +#let align-left-labels() = _config.align-left-labels() + +#let text-family(target, family) = _config.text-family(target, family) +#let text-weight(target, weight) = _config.text-weight(target, weight) +#let text-posture(target, posture) = _config.text-posture(target, posture) +#let text-size(target, size) = _config.text-size(target, size) +#let text-style(target, family, weight, posture, size) = _config.text-style(target, family, weight, posture, size) + +#let caption(text, position: "bottom") = _config.caption(text, position: position) +#let short-caption(text) = _config.short-caption(text) +#let small-separator() = _config.small-separator() +#let medium-separator() = _config.medium-separator() +#let large-separator() = _config.large-separator() +#let no-block-gap() = _config.no-block-gap() +#let small-block-gap() = _config.small-block-gap() +#let medium-block-gap() = _config.medium-block-gap() +#let large-block-gap() = _config.large-block-gap() +#let block-gap(value) = _config.block-gap(value) +#let flexible-block-gap() = _config.flexible-block-gap() +#let fixed-block-gap() = _config.fixed-block-gap() +#let no-line-gap() = _config.no-line-gap() +#let small-line-gap() = _config.small-line-gap() +#let medium-line-gap() = _config.medium-line-gap() +#let large-line-gap() = _config.large-line-gap() +#let line-gap(value) = _config.line-gap(value) +#let feature-slot-space(position, value) = _config.feature-slot-space(position, value) + +#let molecular-weight(sequence, unit: "Da") = _config.molweight(sequence, unit: unit) +#let net-charge(sequence, termini: "o") = _config.charge(sequence, termini: termini) +#let pdb-selection(selection) = _config.pdb-selection(selection) diff --git a/packages/preview/typshade/0.1.3/internal/interface/data.typ b/packages/preview/typshade/0.1.3/internal/interface/data.typ new file mode 100644 index 0000000000..c9bb2fae94 --- /dev/null +++ b/packages/preview/typshade/0.1.3/internal/interface/data.typ @@ -0,0 +1,18 @@ +// Copyright (C) 2026 Eito Yoneyama +// SPDX-License-Identifier: GPL-2.0 + +#import "../model/parser.typ" as _parser + +#let alignment-data(source, format: auto) = _parser.read-alignment(source, format: format) + +#let parse-alignment(text, format: "fasta") = { + let source = _parser._source-text(text) + let normalized = _parser._lower(str(format)) + if normalized == "msf" { + _parser.parse-msf(source) + } else if normalized == "aln" or normalized == "clustal" { + _parser.parse-aln(source) + } else { + _parser.parse-fasta(source) + } +} diff --git a/packages/preview/typshade/0.1.3/internal/interface/inspect.typ b/packages/preview/typshade/0.1.3/internal/interface/inspect.typ new file mode 100644 index 0000000000..09d61c932b --- /dev/null +++ b/packages/preview/typshade/0.1.3/internal/interface/inspect.typ @@ -0,0 +1,151 @@ +// Copyright (C) 2026 Eito Yoneyama +// SPDX-License-Identifier: GPL-2.0 + +#import "../engine/layout.typ" as _layout +#import "../engine/commands.typ" as _commands +#import "../engine/config.typ" as _config +#import "../model/logo.typ" as _logo +#import "../model/parser.typ" as _parser +#import "../render/alignment.typ" as _render + +#let _prepared-alignment(source, format, commands) = { + let config = _config._default-config() + let flat = () + flat = _commands._add-command(flat, commands) + for command in flat { + config = _config._apply-command(config, command) + } + let alignment = _parser.read-alignment(source, format: format) + if config.at("seq-type") != none { + alignment.insert("seq-type", config.at("seq-type")) + } + let _ = _render._validate-config-sequence-refs(alignment, config) + _render._apply-single-sequence-options(alignment, config) + _render._apply-numbering-overrides(alignment, config) + (alignment: alignment, config: config) +} + +#let _debug-value(value) = if value == auto { "auto" } else { str(value) } + +#let _selection-label(selection) = if type(selection) == dictionary and selection.at("kind", default: none) == "typshade-selection" { + selection.at("op", default: "select") +} else { + str(selection) +} + +#let alignment-summary(source, format: auto) = { + let alignment = _parser.read-alignment(source, format: format) + let names = alignment.at("sequences").map(seq => seq.at("name")).join(", ") + table( + columns: (auto, 1fr), + inset: (x: 6pt, y: 3pt), + stroke: (x, y) => if y == 0 { (bottom: 0.6pt) } else { none }, + [Format], [#alignment.at("format")], + [Type], [#alignment.at("seq-type")], + [Sequences], [#str(alignment.at("sequences").len())], + [Columns], [#str(alignment.at("columns"))], + [Names], [#names], + ) +} + +#let selection-preview(source, sequence, selection, format: auto) = { + let alignment = _parser.read-alignment(source, format: format) + let resolved-sequence = alignment.at("sequences").at(_logo._resolve-sequence(alignment, sequence)) + let positions = () + for col in _layout._selection-columns(resolved-sequence, selection, alignment: alignment) { + let pos = resolved-sequence.at("positions").at(col) + if pos != none { + positions.push(str(pos)) + } + } + if positions.len() == 0 { "" } else { positions.join(",") } +} + +#let sequence-list(source, format: auto) = { + let alignment = _parser.read-alignment(source, format: format) + let rows = ([Name], [Length], [Non-gap residues]) + for sequence in alignment.at("sequences") { + let count = sequence.at("positions").filter(pos => pos != none).len() + rows.push([#sequence.at("name")]) + rows.push([#str(sequence.at("aligned").len())]) + rows.push([#str(count)]) + } + table(columns: (1fr, auto, auto), inset: (x: 5pt, y: 3pt), ..rows) +} + +#let selection-table(source, ..items, format: auto, sequence: 1) = { + let rows = ([Name], [Selection], [Positions], [Count]) + for item in items.pos() { + let selection = if type(item) == dictionary { item.at("selection") } else { item } + let name = if type(item) == dictionary and item.keys().contains("name") { item.at("name") } else { _selection-label(selection) } + let item-sequence = if type(item) == dictionary { item.at("sequence", default: sequence) } else { sequence } + let positions = selection-preview(source, item-sequence, selection, format: format) + let count = if positions == "" { 0 } else { positions.split(",").len() } + rows.push([#name]) + rows.push([#_selection-label(selection)]) + rows.push([#positions]) + rows.push([#str(count)]) + } + table(columns: (auto, auto, 1fr, auto), inset: (x: 5pt, y: 3pt), ..rows) +} + +#let alignment-debug(source, format: auto, commands: ()) = { + let prepared = _prepared-alignment(source, format, commands) + let alignment = prepared.at("alignment") + let config = prepared.at("config") + let visible = _render._visible-sequences(alignment, config).map(seq => seq.at("name")).join(", ") + let display-columns = _render._display-columns(alignment, config) + table( + columns: (auto, 1fr), + inset: (x: 6pt, y: 3pt), + stroke: (x, y) => if y == 0 { (bottom: 0.6pt) } else { none }, + [Field], [Value], + [Format], [#alignment.at("format")], + [Type], [#alignment.at("seq-type")], + [Sequences], [#str(alignment.at("sequences").len())], + [Visible sequences], [#visible], + [Columns], [#str(alignment.at("columns"))], + [Displayed columns], [#str(display-columns.len())], + [Residues per line], [#_debug-value(config.at("residues-per-line"))], + [Scoring mode], [#str(config.at("shading").at("mode"))], + [Consensus source], [#str(config.at("consensus").at("source", default: "all"))], + ) +} + +#let cell-inspect(source, sequence, column, format: auto, commands: ()) = { + let prepared = _prepared-alignment(source, format, commands) + let alignment = prepared.at("alignment") + let config = prepared.at("config") + let seq-index = _logo._resolve-sequence(alignment, sequence) + let sequence-data = alignment.at("sequences").at(seq-index) + let col = int(column) - 1 + assert(col >= 0 and col < alignment.at("columns"), message: "typshade: column `" + str(column) + "` is out of range") + let info = _render._style-for-column(alignment, config, col) + let style-info = info.at("styles").at(seq-index) + let cell = ( + char: style-info.at("char"), + fg: style-info.at("fg"), + bg: style-info.at("bg"), + emph: style-info.at("emph", default: false), + frame: none, + rule: style-info.at("rule", default: false), + ) + cell = _render._apply-cell-styles(alignment, config, sequence-data, seq-index, col, info, style-info, cell) + cell = _render._apply-regions(alignment, config, seq-index, col, cell) + table( + columns: (auto, 1fr), + inset: (x: 6pt, y: 3pt), + stroke: (x, y) => if y == 0 { (bottom: 0.6pt) } else { none }, + [Field], [Value], + [Sequence], [#sequence-data.at("name")], + [Column], [#str(column)], + [Position], [#str(sequence-data.at("positions").at(col))], + [Residue], [#sequence-data.at("aligned").slice(col, col + 1)], + [Kind], [#style-info.at("kind", default: "custom")], + [Rendered char], [#cell.at("char")], + [Foreground], [#str(cell.at("fg"))], + [Background], [#str(cell.at("bg"))], + [Consensus], [#str(info.at("consensus"))], + [Consensus score], [#str(calc.round(info.at("consensus-score") * 10) / 10)], + ) +} diff --git a/packages/preview/typshade/0.1.3/internal/interface/presets.typ b/packages/preview/typshade/0.1.3/internal/interface/presets.typ new file mode 100644 index 0000000000..15712af8c5 --- /dev/null +++ b/packages/preview/typshade/0.1.3/internal/interface/presets.typ @@ -0,0 +1,140 @@ +// Copyright (C) 2026 Eito Yoneyama +// SPDX-License-Identifier: GPL-2.0 + +#import "../engine/config.typ" as _config +#import "../engine/commands.typ" as _commands + +#let visual-theme( + colors: none, + mode: none, + option: none, + gap: none, + names: none, + numbering: none, + ruler: none, + legend: none, + commands: (), +) = ( + colors: colors, + mode: mode, + option: option, + gap: gap, + names: names, + numbering: numbering, + ruler: ruler, + legend: legend, + commands: commands, +) + +#let _theme-commands(settings) = { + let out = () + if settings.at("mode", default: none) != none { + out.push(_config.scoring-mode(settings.at("mode"), option: settings.at("option", default: none))) + } + if settings.at("colors", default: none) != none { + out.push(_config.color-scheme(settings.at("colors"))) + } + let gap = settings.at("gap", default: none) + if type(gap) == dictionary { + if gap.at("foreground", default: none) != none or gap.at("background", default: none) != none { + out.push(_config.gap-colors(gap.at("foreground", default: "Black"), gap.at("background", default: "White"))) + } + if gap.at("rule", default: none) != none { + out.push(_config.gap-rule(gap.at("rule"))) + } + } + if settings.at("names", default: none) != none { + out.push(_config.names-color(settings.at("names"))) + } + if settings.at("numbering", default: none) != none { + out.push(_config.numbering-color(settings.at("numbering"))) + } + if settings.at("ruler", default: none) != none { + out.push(_config.ruler-color(settings.at("ruler"))) + } + if settings.at("legend", default: none) != none { + out.push(_config.legend-color(settings.at("legend"))) + } + out = _commands._add-command(out, settings.at("commands", default: ())) + out +} + +#let shade-theme(name) = { + if name == none or name == "classic" { + () + } else if type(name) == dictionary { + _theme-commands(name) + } else if name == "print" or name == "grayscale" { + ( + _config.color-scheme("grays"), + _config.gap-colors("Gray60", "White"), + _config.names-color("Black"), + _config.numbering-color("Gray60"), + ) + } else if name == "screen" or name == "blue" { + ( + _config.color-scheme("blues"), + _config.names-color("RoyalBlue"), + _config.numbering-color("DarkGray"), + ) + } else if name == "warm" { + ( + _config.color-scheme("reds"), + _config.names-color("BrickRed"), + _config.numbering-color("DarkGray"), + ) + } else if name == "nature" or name == "green" { + ( + _config.color-scheme("greens"), + _config.names-color("PineGreen"), + _config.numbering-color("DarkGray"), + ) + } else if type(name) == array { + name + } else { + () + } +} + +#let shade-preset(name) = { + if name == none { + () + } else if name == "publication" { + ( + shade-theme("print"), + _config.names-track(position: "left"), + _config.numbering-track(position: "right"), + _config.consensus-track(position: "bottom"), + _config.residues-per-line(60), + ) + } else if name == "overview" { + ( + _config.fingerprint(1000), + _config.no-numbering-track(), + _config.no-consensus-track(), + _config.align-left-labels(), + ) + } else if name == "logo" { + ( + _config.sequence-logo-track(position: "top"), + _config.logo-scale(position: "leftright"), + _config.consensus-track(position: "bottom"), + ) + } else if name == "functional" { + ( + _config.scoring-mode("functional", option: "charge"), + _config.legend-track(), + ) + } else if name == "structure" { + ( + _config.numbering-track(position: "leftright"), + _config.ruler-track(position: "top", steps: 10), + _config.ruler-color("DarkGray"), + _config.consensus-track(position: "bottom"), + ) + } else if type(name) == array { + name + } else { + () + } +} diff --git a/packages/preview/typshade/0.1.3/internal/interface/recipes.typ b/packages/preview/typshade/0.1.3/internal/interface/recipes.typ new file mode 100644 index 0000000000..54eb1bcecd --- /dev/null +++ b/packages/preview/typshade/0.1.3/internal/interface/recipes.typ @@ -0,0 +1,726 @@ +// Copyright (C) 2026 Eito Yoneyama +// SPDX-License-Identifier: GPL-2.0 + +#import "../engine/config.typ" as _config +#import "../engine/commands.typ" as _commands +#import "../engine/layout.typ": _selection-columns +#import "../model/logo.typ": _resolve-sequence +#import "../model/parser.typ": read-alignment +#import "annotations.typ" as _annotations +#import "tracks.typ": sequence-logo, structure-tracks +#import "presets.typ": shade-preset, shade-theme + +#let _recipe(name, options) = (kind: "typshade-recipe", name: name, options: options) + +#let _is-recipe(value) = type(value) == dictionary and value.at("kind", default: none) == "typshade-recipe" + +#let _add(out, value) = _commands._add-command(out, value) + +#let _value(value, key, default) = if type(value) == dictionary { + value.at(key, default: default) +} else { + default +} + +#let _track-position(value, default) = if value == true { + default +} else if type(value) == dictionary { + value.at("position", default: default) +} else { + value +} + +#let _sequence-index(alignment, sequence) = { + _resolve-sequence(alignment, sequence) +} + +#let _sequence(alignment, sequence) = alignment.at("sequences").at(_sequence-index(alignment, sequence)) + +#let _clamp(value, low, high) = { + if value < low { + low + } else if value > high { + high + } else { + value + } +} + +#let _selection-span(alignment, sequence, selection, padding: 0) = { + let seq = _sequence(alignment, sequence) + let columns = _selection-columns(seq, selection, alignment: alignment) + let first = none + let last = none + for col in columns { + let pos = seq.at("positions").at(col) + if pos != none { + if first == none or pos < first { + first = pos + } + if last == none or pos > last { + last = pos + } + } + } + if first == none or last == none { + none + } else { + let start = _clamp(first - padding, 1, seq.at("length")) + let stop = _clamp(last + padding, 1, seq.at("length")) + str(start) + ".." + str(stop) + } +} + +#let _motif-patterns(motifs) = { + if motifs == none { + return () + } + if type(motifs) == dictionary { + motifs.keys() + } else if type(motifs) == array { + let out = () + for item in motifs { + if type(item) == str { + out.push(item) + } else if type(item) == dictionary { + out.push(_annotation-selection(item, "all")) + } + } + out + } else { + () + } +} + +#let _auto-region(alignment, sequence, motifs, padding: 8) = { + let seq = _sequence(alignment, sequence) + let first = none + let last = none + for pattern in _motif-patterns(motifs) { + let span = _selection-span(alignment, sequence, pattern) + if span != none { + let bounds = span.split("..") + let start = int(bounds.first()) + let stop = int(bounds.last()) + if first == none or start < first { + first = start + } + if last == none or stop > last { + last = stop + } + } + } + if first == none or last == none { + none + } else { + str(_clamp(first - padding, 1, seq.at("length"))) + ".." + str(_clamp(last + padding, 1, seq.at("length"))) + } +} + +#let _has-selection(alignment, sequence, selection) = _selection-span(alignment, sequence, selection) != none + +#let _auto-motifs(alignment, sequence) = { + let candidates = if alignment.at("seq-type") == "N" { + ( + (pattern: "ATG", text: "start"), + (pattern: "TATA", text: "TATA box"), + ) + } else { + ( + (pattern: "NPA", text: "NPA"), + (pattern: "NXX[ST]N", text: "glycosylation"), + (pattern: "CXXC", text: "CXXC"), + (pattern: "HXXH", text: "HXXH"), + ) + } + let out = (:) + for item in candidates { + if _has-selection(alignment, sequence, item.at("pattern")) { + out.insert(item.at("pattern"), item.at("text")) + } + } + out +} + +#let _auto-line-length(alignment, purpose: "publication", region: none, sequence: 1) = { + if region != none and region != auto { + let span = _selection-span(alignment, sequence, region) + if span != none { + let bounds = span.split("..") + return _clamp(int(bounds.last()) - int(bounds.first()) + 1, 35, 90) + } + } + let columns = alignment.at("columns") + let count = alignment.at("sequences").len() + if purpose == "overview" { + if columns <= 120 { columns } else { 120 } + } else if columns <= 55 { + columns + } else if count >= 20 { + 80 + } else if count >= 10 { + 70 + } else { + 60 + } +} + +#let _auto-threshold(alignment, threshold) = { + if threshold != auto { + return threshold + } + if alignment.at("seq-type") == "N" { + 60 + } else { + 45 + } +} + +#let _auto-logo(alignment, logo, region: none) = { + if logo != auto { + return logo + } + let count = alignment.at("sequences").len() + let columns = alignment.at("columns") + let compact = if region == none or region == auto { + columns <= 140 + } else { + true + } + if count >= 4 and compact { + if alignment.at("seq-type") == "N" { "nucleotide" } else { "charge" } + } else { + false + } +} + +#let _auto-conservation(alignment, value) = { + if value == auto { + alignment.at("sequences").len() >= 2 + } else { + value + } +} + +#let _apply-scoring(out, mode, colors, threshold, option: none) = { + if mode != none { + out.push(_config.scoring-mode(mode, option: option)) + } + if colors != none { + out.push(_config.color-scheme(colors)) + } + if threshold != none { + out.push(_config.threshold(threshold)) + } + out +} + +#let _apply-window(out, region, sequence, start: none) = { + if region != none { + if type(region) == dictionary { + out.push(_config.sequence-window( + region.at("sequence", default: sequence), + region.at("selection", default: region.at("range", default: "all")), + start: region.at("start", default: start), + )) + } else { + out.push(_config.sequence-window(sequence, region, start: start)) + } + } + out +} + +#let _apply-ruler(out, value, sequence, every) = { + if value == false or value == none { + return out + } + let position = _track-position(value, "top") + let steps = _value(value, "every", _value(value, "steps", every)) + out.push(_config.ruler-track( + position: position, + sequence: _value(value, "sequence", sequence), + steps: steps, + color: _value(value, "color", none), + )) + if _value(value, "name", none) != none { + out.push(_config.ruler-name(_value(value, "name", none), position: position)) + } + out +} + +#let _apply-consensus(out, value) = { + if value == false or value == none { + return out + } + out.push(_config.consensus-track( + position: _track-position(value, "bottom"), + scale: _value(value, "scale", none), + name: _value(value, "name", none), + )) + out +} + +#let _apply-logo(out, value) = { + if value == false or value == none { + return out + } + if value == true or type(value) == str { + out = _add(out, sequence-logo(position: "top", colors: if value == true { none } else { value })) + } else if type(value) == dictionary { + out = _add(out, sequence-logo( + position: value.at("position", default: "top"), + colors: value.at("colors", default: value.at("colorset", default: none)), + name: value.at("name", default: none), + scale: value.at("scale", default: "leftright"), + relevance-marker: value.at("relevance-marker", default: none), + stretch: value.at("stretch", default: none), + )) + } + out +} + +#let _annotation-selection(item, default) = item.at("selection", default: item.at("range", default: item.at("pattern", default: default))) + +#let _add-motif(out, pattern, settings, sequence, position) = { + if type(settings) == str { + out = _add(out, _annotations.motif(sequence, pattern, text: settings, position: position)) + } else if type(settings) == dictionary { + out = _add(out, _annotations.motif( + settings.at("sequence", default: sequence), + pattern, + text: settings.at("text", default: settings.at("label", default: "motif")), + position: settings.at("position", default: position), + fg: settings.at("fg", default: "White"), + bg: settings.at("bg", default: "RoyalBlue"), + fill: settings.at("fill", default: "Yellow"), + all: settings.at("all", default: false), + )) + } else if settings == true { + out = _add(out, _annotations.motif(sequence, pattern, position: position)) + } + out +} + +#let _apply-motifs(out, motifs, sequence, position: "top") = { + if motifs == none { + return out + } + if type(motifs) == dictionary { + for pattern in motifs.keys() { + out = _add-motif(out, pattern, motifs.at(pattern), sequence, position) + } + } else if type(motifs) == array { + for item in motifs { + if type(item) == str { + out = _add(out, _annotations.motif(sequence, item, position: position)) + } else if type(item) == dictionary { + out = _add-motif( + out, + _annotation-selection(item, "all"), + item, + item.at("sequence", default: sequence), + item.at("position", default: position), + ) + } else { + out = _add(out, item) + } + } + } + out +} + +#let _add-highlight(out, selection, settings, sequence) = { + if type(settings) == dictionary { + out = _add(out, _annotations.highlight( + settings.at("sequence", default: sequence), + selection, + fg: settings.at("fg", default: "White"), + bg: settings.at("bg", default: settings.at("fill", default: "RoyalBlue")), + all: settings.at("all", default: false), + )) + } else if settings == true { + out = _add(out, _annotations.highlight(sequence, selection)) + } else if type(settings) == str { + out = _add(out, _annotations.highlight(sequence, selection, bg: settings)) + } + out +} + +#let _apply-highlights(out, highlights, sequence) = { + if highlights == none { + return out + } + if type(highlights) == dictionary { + for selection in highlights.keys() { + out = _add-highlight(out, selection, highlights.at(selection), sequence) + } + } else if type(highlights) == array { + for item in highlights { + if type(item) == str { + out = _add(out, _annotations.highlight(sequence, item)) + } else if type(item) == dictionary { + out = _add-highlight(out, _annotation-selection(item, "all"), item, sequence) + } else { + out = _add(out, item) + } + } + } + out +} + +#let publication( + mode: "similar", + similarity: "blues", + threshold: auto, + sequence: 1, + region: auto, + line-length: auto, + ruler: true, + every: 10, + conservation: true, + logo: none, + motifs: (:), + highlights: (), + theme: none, + annotations: (), + commands: (), +) = _recipe("publication", ( + mode: mode, + similarity: similarity, + threshold: threshold, + sequence: sequence, + region: region, + line-length: line-length, + ruler: ruler, + every: every, + conservation: conservation, + logo: logo, + motifs: motifs, + highlights: highlights, + theme: theme, + annotations: annotations, + commands: commands, +)) + +#let _build-publication(alignment, options) = { + let mode = options.at("mode") + let similarity = options.at("similarity") + let threshold = _auto-threshold(alignment, options.at("threshold")) + let sequence = options.at("sequence") + let motifs = if options.at("motifs") == auto { _auto-motifs(alignment, sequence) } else { options.at("motifs") } + let region = if options.at("region") == auto { _auto-region(alignment, sequence, motifs) } else { options.at("region") } + let line-length = if options.at("line-length") == auto { + _auto-line-length(alignment, purpose: "publication", region: region, sequence: sequence) + } else { + options.at("line-length") + } + let conservation = _auto-conservation(alignment, options.at("conservation")) + let logo = _auto-logo(alignment, options.at("logo"), region: region) + let out = () + out = _add(out, shade-preset("publication")) + out = _add(out, shade-theme(options.at("theme"))) + out = _apply-scoring(out, mode, similarity, threshold) + if line-length != none { + out.push(_config.residues-per-line(line-length)) + } + out = _apply-window(out, region, sequence) + out = _apply-ruler(out, options.at("ruler"), sequence, options.at("every")) + out = _apply-consensus(out, conservation) + out = _apply-logo(out, logo) + out = _apply-highlights(out, options.at("highlights"), sequence) + out = _apply-motifs(out, motifs, sequence) + out = _add(out, options.at("annotations")) + out = _add(out, options.at("commands")) + out +} + +#let motif-map( + motifs, + sequence: 1, + region: auto, + line-length: auto, + similarity: "blues", + threshold: auto, + logo: auto, + conservation: auto, + graph: auto, + theme: none, + highlights: (), + commands: (), +) = _recipe("motif-map", ( + motifs: motifs, + sequence: sequence, + region: region, + line-length: line-length, + similarity: similarity, + threshold: threshold, + logo: logo, + conservation: conservation, + graph: graph, + theme: theme, + highlights: highlights, + commands: commands, +)) + +#let _build-motif-map(alignment, options) = { + let sequence = options.at("sequence") + let motifs = if options.at("motifs") == auto { _auto-motifs(alignment, sequence) } else { options.at("motifs") } + let region = if options.at("region") == auto { _auto-region(alignment, sequence, motifs) } else { options.at("region") } + let out = _build-publication(alignment, ( + mode: "similar", + similarity: options.at("similarity"), + threshold: options.at("threshold"), + sequence: sequence, + region: region, + line-length: options.at("line-length"), + ruler: true, + every: 10, + conservation: options.at("conservation"), + logo: options.at("logo"), + motifs: motifs, + highlights: options.at("highlights"), + theme: options.at("theme"), + annotations: (), + commands: (), + )) + let graph = if options.at("graph") == auto { alignment.at("sequences").len() >= 3 } else { options.at("graph") } + if graph != false { + if type(graph) == dictionary { + out = _add(out, _annotations.graph( + graph.at("position", default: "bottom"), + graph.at("sequence", default: sequence), + graph.at("selection", default: graph.at("range", default: "all")), + graph.at("metric", default: "conservation"), + kind: graph.at("kind", default: "color"), + options: graph.at("options", default: ("ColdHot",)), + )) + } else { + out = _add(out, _annotations.graph("bottom", sequence, "all", "conservation", kind: "color", options: ("ColdHot",))) + } + } + out = _add(out, options.at("commands")) + out +} + +#let structure-map( + sequence, + topology: none, + secondary: none, + hmmtop: none, + hmmtop-sequence: none, + region: none, + line-length: auto, + similarity: "grays", + threshold: auto, + ruler: true, + conservation: auto, + theme: none, + commands: (), +) = _recipe("structure-map", ( + sequence: sequence, + topology: topology, + secondary: secondary, + hmmtop: hmmtop, + hmmtop-sequence: hmmtop-sequence, + region: region, + line-length: line-length, + similarity: similarity, + threshold: threshold, + ruler: ruler, + conservation: conservation, + theme: theme, + commands: commands, +)) + +#let _build-structure-map(alignment, options) = { + let sequence = options.at("sequence") + let region = options.at("region") + let line-length = if options.at("line-length") == auto { + _auto-line-length(alignment, purpose: "structure", region: region, sequence: sequence) + } else { + options.at("line-length") + } + let threshold = if options.at("threshold") == auto { none } else { options.at("threshold") } + let conservation = _auto-conservation(alignment, options.at("conservation")) + let out = () + out = _add(out, shade-preset("structure")) + out = _add(out, shade-theme(options.at("theme"))) + out = _apply-scoring(out, "similar", options.at("similarity"), threshold) + if line-length != none { + out.push(_config.residues-per-line(line-length)) + } + out = _apply-window(out, region, sequence) + out = _apply-ruler(out, options.at("ruler"), sequence, 10) + out = _apply-consensus(out, conservation) + out = _add(out, structure-tracks( + sequence, + hmmtop: options.at("hmmtop"), + topology: options.at("topology"), + secondary: options.at("secondary"), + hmmtop-sequence: options.at("hmmtop-sequence"), + )) + out = _add(out, options.at("commands")) + out +} + +#let logo-analysis( + sequence: 1, + region: none, + line-length: auto, + colors: auto, + subfamily: none, + negative: auto, + relevance: auto, + conservation: auto, + theme: none, + commands: (), +) = _recipe("logo-analysis", ( + sequence: sequence, + region: region, + line-length: line-length, + colors: colors, + subfamily: subfamily, + negative: negative, + relevance: relevance, + conservation: conservation, + theme: theme, + commands: commands, +)) + +#let _build-logo-analysis(alignment, options) = { + let sequence = options.at("sequence") + let region = options.at("region") + let line-length = if options.at("line-length") == auto { + _auto-line-length(alignment, purpose: "logo", region: region, sequence: sequence) + } else { + options.at("line-length") + } + let colors = if options.at("colors") == auto { + if alignment.at("seq-type") == "N" { "nucleotide" } else { "charge" } + } else { + options.at("colors") + } + let conservation = _auto-conservation(alignment, options.at("conservation")) + let out = () + out = _add(out, shade-preset("logo")) + out = _add(out, shade-theme(options.at("theme"))) + if line-length != none { + out.push(_config.residues-per-line(line-length)) + } + out = _apply-window(out, region, sequence) + out = _add(out, sequence-logo(position: "top", colors: colors)) + if options.at("subfamily") != none { + out.push(_config.subfamily(options.at("subfamily"))) + out.push(_config.subfamily-logo-track(position: "bottom", colorset: colors)) + } + let negative = if options.at("negative") == auto { options.at("subfamily") != none } else { options.at("negative") } + if negative { + out.push(_config.negative-logo-values()) + } + let relevance = if options.at("relevance") == auto and options.at("subfamily") != none { 1.0 } else { options.at("relevance") } + if relevance != none and relevance != auto { + if type(relevance) == dictionary { + out.push(_config.relevance-marker( + char: relevance.at("char", default: "*"), + color: relevance.at("color", default: "Black"), + )) + if relevance.at("threshold", default: none) != none { + out.push(_config.relevance-threshold(relevance.at("threshold"))) + } + } else { + out.push(_config.relevance-threshold(relevance)) + } + } + out = _apply-consensus(out, conservation) + out = _add(out, options.at("commands")) + out +} + +#let overview( + mode: "similar", + colors: none, + line-length: auto, + names: true, + numbers: false, + conservation: false, + ruler: false, + theme: none, + commands: (), +) = _recipe("overview", ( + mode: mode, + colors: colors, + line-length: line-length, + names: names, + numbers: numbers, + conservation: conservation, + ruler: ruler, + theme: theme, + commands: commands, +)) + +#let _build-overview(alignment, options) = { + let line-length = if options.at("line-length") == auto { + _auto-line-length(alignment, purpose: "overview") + } else { + options.at("line-length") + } + let out = () + out = _add(out, shade-preset("overview")) + out = _add(out, shade-theme(options.at("theme"))) + out = _apply-scoring(out, options.at("mode"), options.at("colors"), none) + if line-length != none { + out.push(_config.residues-per-line(line-length)) + } + let names = options.at("names") + if names == false { + out.push(_config.no-names-track()) + } else if names != true { + out.push(_config.names-track(position: _track-position(names, "left"), color: _value(names, "color", none))) + } + let numbers = options.at("numbers") + if numbers == true or type(numbers) == dictionary or type(numbers) == str { + out.push(_config.numbering-track(position: _track-position(numbers, "right"), color: _value(numbers, "color", none))) + } + out = _apply-consensus(out, options.at("conservation")) + out = _apply-ruler(out, options.at("ruler"), 1, 10) + out = _add(out, options.at("commands")) + out +} + +#let _build-recipe(alignment, item) = { + let name = item.at("name") + let options = item.at("options") + if name == "publication" { + _build-publication(alignment, options) + } else if name == "motif-map" { + _build-motif-map(alignment, options) + } else if name == "structure-map" { + _build-structure-map(alignment, options) + } else if name == "logo-analysis" { + _build-logo-analysis(alignment, options) + } else if name == "overview" { + _build-overview(alignment, options) + } else { + () + } +} + +#let resolve-figure(source, format, figure) = { + let out = () + let items = if type(figure) == array { figure } else { (figure,) } + let needs-alignment = false + for item in items { + if _is-recipe(item) { + needs-alignment = true + } + } + let alignment = if needs-alignment { read-alignment(source, format: format) } else { none } + for item in items { + if _is-recipe(item) { + out = _add(out, _build-recipe(alignment, item)) + } else { + out = _add(out, item) + } + } + out +} diff --git a/packages/preview/typshade/0.1.3/internal/interface/selection.typ b/packages/preview/typshade/0.1.3/internal/interface/selection.typ new file mode 100644 index 0000000000..0a8db3943a --- /dev/null +++ b/packages/preview/typshade/0.1.3/internal/interface/selection.typ @@ -0,0 +1,64 @@ +// Copyright (C) 2026 Eito Yoneyama +// SPDX-License-Identifier: GPL-2.0 + +#let _selection(op, fields) = { + let out = fields + out.insert("kind", "typshade-selection") + out.insert("op", op) + out +} + +#let select(..items, mode: "or", padding: 0) = _selection(mode, ( + items: items.pos(), + padding: padding, +)) + +#let select-or(..items, padding: 0) = select(..items.pos(), mode: "or", padding: padding) + +#let select-and(..items, padding: 0) = select(..items.pos(), mode: "and", padding: padding) + +#let select-not(selection) = _selection("not", (selection: selection)) + +#let select-pad(selection, before, after: none) = _selection("pad", ( + selection: selection, + before: before, + after: if after == none { before } else { after }, +)) + +#let select-all() = _selection("all", (:)) + +#let select-range(start, ..args) = { + let positional = args.pos() + let stop = if positional.len() > 0 { positional.first() } else { args.named().at("stop", default: none) } + if stop == none and type(start) == str { + _selection("range", (range: start)) + } else { + _selection("range", (start: start, stop: if stop == none { start } else { stop })) + } +} + +#let select-residues(..positions) = _selection("positions", (positions: positions.pos())) + +#let select-motif(pattern) = _selection("motif", (pattern: pattern)) + +#let select-metric( + metric, + above: none, + below: none, + at-least: none, + at-most: none, + min: none, + max: none, + equals: none, + selection: "all", +) = _selection("metric", ( + metric: metric, + above: above, + below: below, + at-least: at-least, + at-most: at-most, + min: min, + max: max, + equals: equals, + selection: selection, +)) diff --git a/packages/preview/typshade/0.1.3/internal/interface/shade.typ b/packages/preview/typshade/0.1.3/internal/interface/shade.typ new file mode 100644 index 0000000000..1415770c2f --- /dev/null +++ b/packages/preview/typshade/0.1.3/internal/interface/shade.typ @@ -0,0 +1,163 @@ +// Copyright (C) 2026 Eito Yoneyama +// SPDX-License-Identifier: GPL-2.0 + +#import "../engine/config.typ" as _config +#import "../engine/commands.typ" as _commands +#import "recipes.typ" as _recipes +#import "presets.typ": shade-preset, shade-theme +#import "../render/alignment.typ" as _render + +#let _typst-figure = figure + +#let _position-value(value, default) = if value == true { + default +} else { + value +} + +#let _value-or-default(value, key, default) = if type(value) == dictionary { + value.at(key, default: default) +} else { + default +} + +#let shade( + source, + format: auto, + figure: (), + preset: none, + theme: none, + mode: none, + option: none, + seq-type: auto, + residues-per-line: none, + fit: none, + names: none, + numbering: none, + consensus: none, + ruler: none, + logo: none, + subfamily-logo: none, + legend: none, + regions: (), + features: (), + commands: (), + caption: none, + short-caption: none, + font: none, + font-size: none, +) = { + let out = () + out = _commands._add-command(out, _recipes.resolve-figure(source, format, figure)) + out = _commands._add-command(out, shade-preset(preset)) + out = _commands._add-command(out, shade-theme(theme)) + if seq-type != auto and seq-type != none { + out.push(_config.sequence-type(seq-type)) + } + if mode != none { + out.push(_config.scoring-mode(mode, option: option)) + } + if residues-per-line != none { + out.push(_config.residues-per-line(residues-per-line)) + } + if fit != none { + if type(fit) == dictionary { + let fit-mode = fit.at("mode", default: fit.at("fit", default: "container")) + out.push(_config.auto-layout( + fit: fit-mode, + min: fit.at("min", default: 1), + max: fit.at("max", default: none), + )) + if fit-mode == "page" or fit.at("page", default: false) != false { + let page = fit.at("page", default: false) + if type(page) == dictionary { + out.push(_config.auto-page(blocks: page.at("blocks", default: auto), repeat-legend: page.at("repeat-legend", default: true))) + } else { + out.push(_config.auto-page()) + } + } + } else if fit != false { + out.push(_config.auto-layout(fit: if fit == true { "container" } else { fit })) + if fit == "page" { + out.push(_config.auto-page()) + } + } + } + if names != none { + if names == false { + out.push(_config.no-names-track()) + } else { + out.push(_config.names-track(position: _position-value(names, "left"))) + } + } + if numbering != none { + if numbering == false { + out.push(_config.no-numbering-track()) + } else { + out.push(_config.numbering-track(position: _position-value(numbering, "right"))) + } + } + if consensus != none { + if consensus == false { + out.push(_config.no-consensus-track()) + } else { + out.push(_config.consensus-track(position: _position-value(consensus, "bottom"))) + } + } + if ruler != none { + if ruler == false { + out.push(_config.no-ruler-track()) + } else if type(ruler) == dictionary { + out.push(_config.ruler-track( + position: ruler.at("position", default: "top"), + sequence: ruler.at("sequence", default: 1), + steps: ruler.at("steps", default: none), + color: ruler.at("color", default: none), + )) + } else { + out.push(_config.ruler-track(position: _position-value(ruler, "top"))) + } + } + if logo != none { + if logo == false { + out.push(_config.no-sequence-logo-track()) + } else if type(logo) == dictionary { + out.push(_config.sequence-logo-track(position: logo.at("position", default: "top"), colorset: logo.at("colorset", default: none))) + } else { + out.push(_config.sequence-logo-track(position: _position-value(logo, "top"))) + } + } + if subfamily-logo != none { + if subfamily-logo == false { + out.push(_config.no-subfamily-logo-track()) + } else if type(subfamily-logo) == dictionary { + if subfamily-logo.keys().contains("sequences") { + out.push(_config.subfamily(subfamily-logo.at("sequences"))) + } + out.push(_config.subfamily-logo-track(position: subfamily-logo.at("position", default: "top"), colorset: subfamily-logo.at("colorset", default: none))) + } else { + out.push(_config.subfamily-logo-track(position: _position-value(subfamily-logo, "top"))) + } + } + if legend != none { + if legend == false { + out.push(_config.no-legend-track()) + } else if type(legend) == dictionary { + out.push(_config.legend-track(color: legend.at("color", default: "Black"))) + } else { + out.push(_config.legend-track()) + } + } + out = _commands._add-command(out, regions) + out = _commands._add-command(out, features) + out = _commands._add-command(out, commands) + if short-caption != none { + out.push(_config.short-caption(short-caption)) + } + let rendered = _render.render-alignment(source, format: format, commands: out, font: font, font-size: font-size) + if caption == none { + rendered + } else { + _typst-figure(rendered, caption: caption) + } +} diff --git a/packages/preview/typshade/0.1.3/internal/interface/shortcuts.typ b/packages/preview/typshade/0.1.3/internal/interface/shortcuts.typ new file mode 100644 index 0000000000..f9f4d097eb --- /dev/null +++ b/packages/preview/typshade/0.1.3/internal/interface/shortcuts.typ @@ -0,0 +1,164 @@ +// Copyright (C) 2026 Eito Yoneyama +// SPDX-License-Identifier: GPL-2.0 + +#import "../engine/config.typ" as _config +#import "annotations.typ": highlight, tint, emphasize, mark, motif, graph +#import "tracks.typ": consensus-track, ruler-track, sequence-logo, legend-track, structure-tracks + +#let _scoring( + mode, + colors: none, + threshold: none, + option: none, + all-match-threshold: none, + weight-table: none, + gap-penalty: none, +) = { + let out = (_config.scoring-mode(mode, option: option),) + if colors != none { + out.push(_config.color-scheme(colors)) + } + if threshold != none { + out.push(_config.threshold(threshold)) + } + if all-match-threshold != none { + out.push(_config.all-match-threshold(value: all-match-threshold)) + } + if weight-table != none { + out.push(_config.weight-table(weight-table)) + } + if gap-penalty != none { + out.push(_config.gap-penalty(gap-penalty)) + } + out +} + +#let identical(colors: none, threshold: none, option: none, ..rest) = _scoring( + "identical", + colors: colors, + threshold: threshold, + option: option, + ..rest, +) + +#let similar(colors: none, threshold: none, option: none, ..rest) = _scoring( + "similar", + colors: colors, + threshold: threshold, + option: option, + ..rest, +) + +#let diverse(colors: none, threshold: none, option: none, ..rest) = _scoring( + "diverse", + colors: colors, + threshold: threshold, + option: option, + ..rest, +) + +#let functional(kind, colors: none, threshold: none, ..rest) = _scoring( + "functional", + colors: colors, + threshold: threshold, + option: kind, + ..rest, +) + +#let single-sequence(colors: none, threshold: none, sequence: none, ..rest) = _scoring( + "singleseq", + colors: colors, + threshold: threshold, + option: sequence, + ..rest, +) + +#let tcoffee(source) = _config.scoring-mode("T-Coffee", option: source) + +#let lines(count) = _config.residues-per-line(count) + +#let window(sequence, selection, start: none) = _config.sequence-window(sequence, selection, start: start) + +#let names(position: "left", color: none) = _config.names-track(position: position, color: color) + +#let no-names() = _config.no-names-track() + +#let numbers(position: "right", color: none) = _config.numbering-track(position: position, color: color) + +#let no-numbers() = _config.no-numbering-track() + +#let consensus(position, scale: none, name: none) = consensus-track(position: position, scale: scale, name: name) + +#let no-consensus() = _config.no-consensus-track() + +#let ruler(position, sequence: 1, every: none, steps: none, color: none, name: none, name-color: none, space: none) = { + ruler-track( + position: position, + sequence: sequence, + steps: if steps == none { every } else { steps }, + color: color, + name: name, + name-color: name-color, + space: space, + ) +} + +#let no-ruler(position: none) = _config.no-ruler-track(position: position) + +#let logo(position, colors: none, name: none, scale: "leftright", relevance-marker: none, stretch: none) = { + sequence-logo( + position: position, + colors: colors, + name: name, + scale: scale, + relevance-marker: relevance-marker, + stretch: stretch, + ) +} + +#let no-logo() = _config.no-sequence-logo-track() + +#let legend(color: "Black") = legend-track(color: color) + +#let no-legend() = _config.no-legend-track() + +#let structures(sequence, hmmtop: none, topology: none, secondary: none, hmmtop-sequence: none) = { + structure-tracks( + sequence, + hmmtop: hmmtop, + topology: topology, + secondary: secondary, + hmmtop-sequence: hmmtop-sequence, + ) +} + +#let gap-style(foreground: none, background: none, rule: none) = { + let out = () + if foreground != none or background != none { + out.push(_config.gap-colors( + if foreground == none { "Black" } else { foreground }, + if background == none { "White" } else { background }, + )) + } + if rule != none { + out.push(_config.gap-rule(rule)) + } + out +} + +#let typography(target: "all", family: none, weight: none, posture: none, size: none) = { + let out = () + if family != none { + out.push(_config.text-family(target, family)) + } + if weight != none { + out.push(_config.text-weight(target, weight)) + } + if posture != none { + out.push(_config.text-posture(target, posture)) + } + if size != none { + out.push(_config.text-size(target, size)) + } + out +} diff --git a/packages/preview/typshade/0.1.3/internal/interface/tracks.typ b/packages/preview/typshade/0.1.3/internal/interface/tracks.typ new file mode 100644 index 0000000000..39923dd96a --- /dev/null +++ b/packages/preview/typshade/0.1.3/internal/interface/tracks.typ @@ -0,0 +1,77 @@ +// Copyright (C) 2026 Eito Yoneyama +// SPDX-License-Identifier: GPL-2.0 + +#import "../engine/config.typ" as _config + +#let consensus-track(position: "bottom", scale: none, name: none) = _config.consensus-track(position: position, scale: scale, name: name) +#let no-consensus() = _config.no-consensus-track() + +#let ruler-track(position: "top", sequence: 1, steps: none, color: none, name: none, name-color: none, space: none) = { + let out = (_config.ruler-track(position: position, sequence: sequence, steps: steps, color: color),) + if name != none { + out.push(_config.ruler-name(name, position: position)) + } + if color != none { + out.push(_config.ruler-color(color, position: position)) + } + if name-color != none { + out.push(_config.ruler-name-color(name-color, position: position)) + } + if space != none { + out.push(_config.ruler-space(space, position: position)) + } + out +} + +#let ruler-marker(number, text, position: "top", color: none) = _config.ruler-marker(number, text, position: position, color: color) +#let no-ruler(position: none) = _config.no-ruler-track(position: position) + +#let sequence-logo(position: "top", colors: none, name: none, scale: "leftright", relevance-marker: none, stretch: none) = { + let out = (_config.sequence-logo-track(position: position, colorset: colors),) + if name != none { + out.push(_config.sequence-logo-name(name)) + } + if scale == false { + out.push(_config.no-logo-scale()) + } else if scale != none { + out.push(_config.logo-scale(position: scale)) + } + if relevance-marker != none { + out.push(_config.relevance-marker(char: relevance-marker.at("char", default: "*"), color: relevance-marker.at("color", default: "Black"))) + if relevance-marker.at("threshold", default: none) != none { + out.push(_config.relevance-threshold(relevance-marker.at("threshold"))) + } + } + if stretch != none { + out.push(_config.logo-stretch(stretch)) + } + out +} + +#let no-sequence-logo() = _config.no-sequence-logo-track() + +#let subfamily-logo(sequences, position: "bottom", colors: none, name: none, negative-name: none) = { + let out = (_config.subfamily(sequences), _config.subfamily-logo-track(position: position, colorset: colors)) + if name != none or negative-name != none { + out.push(_config.subfamily-logo-name(if name == none { "subfamily" } else { name }, negative-name: negative-name)) + } + out +} + +#let no-subfamily-logo() = _config.no-subfamily-logo-track() + +#let legend-track(color: "Black") = _config.legend-track(color: color) + +#let structure-tracks(sequence, hmmtop: none, topology: none, secondary: none, hmmtop-sequence: none) = { + let out = () + if hmmtop != none { + out.push(_config.hmmtop-track(sequence, hmmtop, source-sequence: hmmtop-sequence)) + } + if topology != none { + out.push(_config.phd-topology-track(sequence, topology)) + } + if secondary != none { + out.push(_config.phd-secondary-track(sequence, secondary)) + } + out +} diff --git a/packages/preview/typshade/0.1.3/internal/model/logo.typ b/packages/preview/typshade/0.1.3/internal/model/logo.typ new file mode 100644 index 0000000000..9e16680b83 --- /dev/null +++ b/packages/preview/typshade/0.1.3/internal/model/logo.typ @@ -0,0 +1,181 @@ +// Copyright (C) 2026 Eito Yoneyama +// SPDX-License-Identifier: GPL-2.0 + +#import "palette.typ": _default-logo-colors, _functional-presets, _logo-color-presets +#import "parser.typ": _upper + +#let _log2(value) = calc.log(value) / calc.log(2) +#let _logo-max-bits(seq-type) = if seq-type == "N" { 2.0 } else { _log2(20.0) } + +#let _sequence-reference-message(alignment) = { + let names = alignment.at("sequences").map(seq => seq.at("name")).join(", ") + "expected a 1-based sequence index from 1 to " + str(alignment.at("sequences").len()) + " or one of: " + names +} + +#let _resolve-sequence(alignment, sequence) = { + if type(sequence) == int { + assert( + sequence >= 1 and sequence <= alignment.at("sequences").len(), + message: "typshade: sequence index `" + str(sequence) + "` is out of range; " + _sequence-reference-message(alignment), + ) + return sequence - 1 + } + let ref = str(sequence) + for (idx, seq) in alignment.at("sequences").enumerate() { + if seq.at("name") == ref { + return idx + } + } + if ref.matches(regex("^\\d+$")).len() > 0 { + let index = int(ref) + assert( + index >= 1 and index <= alignment.at("sequences").len(), + message: "typshade: sequence index `" + ref + "` is out of range; " + _sequence-reference-message(alignment), + ) + return index - 1 + } + assert( + false, + message: "typshade: unknown sequence `" + ref + "`; " + _sequence-reference-message(alignment), + ) +} + +#let _functional-style(residue, mode) = { + if not _functional-presets.keys().contains(mode) { + return none + } + for group in _functional-presets.at(mode) { + if group.at("residues").contains(residue) { + return group + } + } + none +} + +#let _logo-preset(seq-type, colorset) = { + if colorset == none { + return if seq-type == "N" { "nucleotide" } else { "rasmol" } + } + let key = str(colorset) + if key == "standard" { + return if seq-type == "N" { "nucleotide" } else { "rasmol" } + } + key +} + +#let _logo-frequencies(alignment, col, subset: none, subfamily: false) = { + let counts = (:) + let rest = (:) + let total = 0 + let total-rest = 0 + let use-all = subset == none or subset.len() == 0 + for (idx, seq) in alignment.at("sequences").enumerate() { + let char = _upper(seq.at("aligned").slice(col, col + 1)) + if char == "." or char == "-" or char == "" { + continue + } + let in-subset = use-all or subset.contains(seq.at("name")) or subset.contains(idx + 1) + if not subfamily { + if in-subset { + counts.insert(char, counts.at(char, default: 0) + 1) + total += 1 + } + } else if in-subset { + counts.insert(char, counts.at(char, default: 0) + 1) + total += 1 + } else { + rest.insert(char, rest.at(char, default: 0) + 1) + total-rest += 1 + } + } + if not subfamily { + return (counts: counts, total: total) + } + let diffs = (:) + for key in counts.keys() { + let left = if total == 0 { 0.0 } else { counts.at(key) / total } + let right = if total-rest == 0 { 0.0 } else { rest.at(key, default: 0) / total-rest } + diffs.insert(key, left - right) + } + for key in rest.keys() { + if not diffs.keys().contains(key) { + let right = if total-rest == 0 { 0.0 } else { rest.at(key) / total-rest } + diffs.insert(key, -right) + } + } + (counts: diffs, total: 1) +} + +#let _logo-color(seq-type, colorset, residue) = { + let key = _upper(residue) + if type(colorset) == dictionary and colorset.keys().contains(key) { + return colorset.at(key) + } + let preset = _logo-preset(seq-type, colorset) + if _logo-color-presets.keys().contains(preset) { + for entry in _logo-color-presets.at(preset) { + if entry.at("residues").contains(key) { + return entry.at("color") + } + } + } + if colorset != none and _functional-presets.keys().contains(colorset) { + let group = _functional-style(key, colorset) + if group != none { + return group.at("bg") + } + } + _default-logo-colors.at(seq-type).at(key, default: "Black") +} + +#let _logo-colorset(config, residue, subfamily: false) = { + let custom = config.at("logo-colors").at("map") + let key = _upper(residue) + if custom.keys().contains(key) or config.at("logo-colors").at("default") != none { + return custom + (default: config.at("logo-colors").at("default")) + } + if subfamily { + return config.at("subfamily-logo").at("colorset") + } + config.at("sequence-logo").at("colorset") +} + +#let _logo-residue-color(config, seq-type, residue, subfamily: false) = { + _logo-color(seq-type, _logo-colorset(config, residue, subfamily: subfamily), residue) +} + +#let _logo-column-items(alignment, config, col, subfamily: false) = { + let subset = if subfamily { config.at("subfamily") } else { none } + let data = _logo-frequencies(alignment, col, subset: subset, subfamily: subfamily) + let counts = data.at("counts") + if counts.keys().len() == 0 { + return () + } + let seq-type = alignment.at("seq-type") + let heights = () + if not subfamily { + let total = data.at("total") + let entropy = 0.0 + for key in counts.keys() { + let p = counts.at(key) / total + if p > 0 { + entropy += -p * _log2(p) + } + } + let correction = if config.at("frequency-correction") and total > 0 { + (counts.keys().len() - 1) / (2.0 * calc.log(2) * total) + } else { + 0.0 + } + let info = calc.max(0.0, _logo-max-bits(seq-type) - entropy - correction) + for key in counts.keys() { + let p = counts.at(key) / total + heights.push((residue: key, value: p * info)) + } + } else { + for key in counts.keys() { + heights.push((residue: key, value: counts.at(key) * _logo-max-bits(seq-type))) + } + } + heights.sorted(key: it => calc.abs(it.at("value"))).filter(it => calc.abs(it.at("value")) > 0) +} diff --git a/packages/preview/typshade/0.1.3/internal/model/palette.typ b/packages/preview/typshade/0.1.3/internal/model/palette.typ new file mode 100644 index 0000000000..88d5b3239e --- /dev/null +++ b/packages/preview/typshade/0.1.3/internal/model/palette.typ @@ -0,0 +1,460 @@ +// Copyright (C) 2026 Eito Yoneyama +// SPDX-License-Identifier: GPL-2.0 + +#let _color-db = ( + Black: (0, 0, 0), + White: (255, 255, 255), + Gray: (128, 128, 128), + Gray0: (255, 255, 255), + Gray5: (242, 242, 242), + Gray10: (230, 230, 230), + Gray15: (217, 217, 217), + Gray20: (204, 204, 204), + Gray25: (191, 191, 191), + Gray30: (179, 179, 179), + LightGray: (171, 171, 171), + Gray35: (166, 166, 166), + Gray40: (153, 153, 153), + Gray45: (140, 140, 140), + Gray50: (128, 128, 128), + Gray55: (115, 115, 115), + Gray60: (102, 102, 102), + Gray65: (89, 89, 89), + DarkGray: (87, 87, 87), + Gray70: (77, 77, 77), + Gray75: (64, 64, 64), + Gray80: (51, 51, 51), + Gray85: (38, 38, 38), + Gray90: (26, 26, 26), + Gray95: (13, 13, 13), + Red: (255, 0, 0), + Blue: (0, 0, 255), + Green: (0, 255, 0), + Magenta: (255, 0, 255), + Cyan: (0, 255, 255), + Yellow: (255, 255, 0), + Orange: (255, 99, 33), + YellowOrange: (255, 148, 0), + YellowGreen: (217, 255, 79), + Goldenrod: (255, 230, 41), + GreenYellow: (217, 255, 79), + RoyalBlue: (0, 128, 255), + RoyalPurple: (64, 25, 255), + PineGreen: (15, 191, 105), + OliveGreen: (55, 153, 8), + BrickRed: (184, 28, 15), + Mahagony: (166, 25, 22), + Brown: (102, 19, 0), + MidnightBlue: (3, 126, 255), + CornflowerBlue: (89, 222, 255), + Apricot: (255, 173, 122), + SkyBlue: (97, 255, 224), + RedViolet: (157, 17, 168), + CarnationPink: (255, 166, 255), + LightMagenta: (255, 128, 255), + LightBlue: (128, 128, 255), + LightGreen: (128, 255, 128), + LightRed: (255, 128, 128), + LightBrown: (179, 107, 89), + TC0: (153, 153, 255), + TC1: (102, 255, 77), + TC2: (153, 255, 77), + TC3: (204, 255, 0), + TC4: (255, 255, 0), + TC5: (255, 204, 0), + TC6: (255, 153, 0), + TC7: (255, 102, 0), + TC8: (255, 51, 0), + TC9: (255, 32, 0), + BlackWhite0: (0, 0, 0), + BlackWhite5: (13, 13, 13), + BlackWhite10: (26, 26, 26), + BlackWhite15: (38, 38, 38), + BlackWhite20: (51, 51, 51), + BlackWhite25: (64, 64, 64), + BlackWhite30: (77, 77, 77), + BlackWhite35: (89, 89, 89), + BlackWhite40: (102, 102, 102), + BlackWhite45: (115, 115, 115), + BlackWhite50: (128, 128, 128), + BlackWhite55: (140, 140, 140), + BlackWhite60: (153, 153, 153), + BlackWhite65: (166, 166, 166), + BlackWhite70: (179, 179, 179), + BlackWhite75: (191, 191, 191), + BlackWhite80: (204, 204, 204), + BlackWhite85: (217, 217, 217), + BlackWhite90: (230, 230, 230), + BlackWhite95: (242, 242, 242), + BlackWhite100: (255, 255, 255), + WhiteBlack0: (255, 255, 255), + WhiteBlack5: (242, 242, 242), + WhiteBlack10: (230, 230, 230), + WhiteBlack15: (217, 217, 217), + WhiteBlack20: (204, 204, 204), + WhiteBlack25: (191, 191, 191), + WhiteBlack30: (179, 179, 179), + WhiteBlack35: (166, 166, 166), + WhiteBlack40: (153, 153, 153), + WhiteBlack45: (140, 140, 140), + WhiteBlack50: (128, 128, 128), + WhiteBlack55: (115, 115, 115), + WhiteBlack60: (102, 102, 102), + WhiteBlack65: (89, 89, 89), + WhiteBlack70: (77, 77, 77), + WhiteBlack75: (64, 64, 64), + WhiteBlack80: (51, 51, 51), + WhiteBlack85: (38, 38, 38), + WhiteBlack90: (26, 26, 26), + WhiteBlack95: (13, 13, 13), + WhiteBlack100: (0, 0, 0), + BrewerA: (51, 255, 0), + BrewerC: (166, 237, 255), + BrewerG: (25, 179, 255), + BrewerT: (179, 255, 140), +) + +#let _scale-db = ( + BlueRed: ( + (0, (26, 26, 128)), + (25, (110, 110, 173)), + (50, (219, 209, 209)), + (75, (232, 99, 94)), + (100, (222, 41, 10)), + ), + RedBlue: ( + (0, (222, 38, 10)), + (25, (232, 99, 94)), + (50, (219, 209, 209)), + (75, (110, 110, 173)), + (100, (38, 43, 140)), + ), + GreenRed: ( + (0, (0, 255, 0)), + (50, (115, 140, 0)), + (100, (242, 13, 0)), + ), + RedGreen: ( + (0, (255, 0, 0)), + (50, (140, 115, 0)), + (100, (13, 242, 0)), + ), + ColdHot: ( + (0, (0, 0, 255)), + (25, (0, 230, 255)), + (50, (0, 255, 10)), + (75, (250, 255, 0)), + (100, (232, 0, 0)), + ), + HotCold: ( + (0, (255, 0, 0)), + (25, (255, 153, 0)), + (50, (41, 255, 0)), + (75, (0, 255, 222)), + (100, (0, 20, 255)), + ), + TCoffee: ( + (0, (153, 153, 255)), + (10, (102, 255, 77)), + (20, (153, 255, 77)), + (30, (204, 255, 0)), + (40, (255, 255, 0)), + (50, (255, 204, 0)), + (60, (255, 153, 0)), + (70, (255, 102, 0)), + (80, (255, 51, 0)), + (90, (255, 32, 0)), + (100, (255, 32, 0)), + ), +) + +#let _pep-groups = ( + "FYW", + "ILVM", + "RK", + "DE", + "GA", + "ST", + "NQ", +) + +#let _pep-sims = ( + F: "YW", + Y: "WF", + W: "YF", + I: "LVM", + L: "VMI", + V: "MIL", + R: "KH", + K: "HR", + H: "RK", + A: "GS", + G: "A", + S: "TA", + T: "S", + D: "EN", + E: "DQ", + N: "QD", + Q: "NE", +) + +#let _dna-groups = ( + "GAR", + "CTY", +) + +#let _dna-sims = ( + A: "GR", + G: "AR", + R: "AG", + C: "TY", + T: "CY", + Y: "CT", +) + +#let _functional-presets = ( + charge: ( + (name: "acidic (-)", residues: "DE", fg: "White", bg: "Red"), + (name: "basic (+)", residues: "KRH", fg: "White", bg: "Blue"), + ), + hydropathy: ( + (name: "acidic (-)", residues: "DE", fg: "White", bg: "Red"), + (name: "basic (+)", residues: "KRH", fg: "White", bg: "Blue"), + (name: "polar uncharged", residues: "YSTGNQC", fg: "Black", bg: "Yellow"), + (name: "hydrophobic nonpolar", residues: "AFPMWVIL", fg: "White", bg: "Green"), + ), + structure: ( + (name: "external", residues: "DEHKNQR", fg: "Black", bg: "Orange"), + (name: "ambivalent", residues: "ACGPSTWY", fg: "Black", bg: "Yellow"), + (name: "internal", residues: "FILMV", fg: "White", bg: "Green"), + ), + chemical: ( + (name: "acidic (-)", residues: "DE", fg: "White", bg: "Red"), + (name: "aliphatic", residues: "AGVIL", fg: "White", bg: "Black"), + (name: "aliphatic (small)", residues: "AG", fg: "White", bg: "Gray"), + (name: "amide", residues: "NQ", fg: "White", bg: "Green"), + (name: "aromatic", residues: "FYW", fg: "White", bg: "Brown"), + (name: "basic (+)", residues: "KRH", fg: "White", bg: "Blue"), + (name: "hydroxyl", residues: "ST", fg: "Black", bg: "Magenta"), + (name: "imino", residues: "P", fg: "Black", bg: "Orange"), + (name: "sulfur", residues: "CM", fg: "Black", bg: "Yellow"), + ), + rasmol: ( + (name: "Asp, Glu", residues: "DE", fg: "Red", bg: "White"), + (name: "Arg, Lys, His", residues: "KRH", fg: "Blue", bg: "White"), + (name: "Phe, Tyr, Trp", residues: "FYW", fg: "MidnightBlue", bg: "White"), + (name: "Ala, Gly", residues: "AG", fg: "Gray", bg: "White"), + (name: "Cys, Met", residues: "CM", fg: "Yellow", bg: "White"), + (name: "Ser, Thr", residues: "ST", fg: "Orange", bg: "White"), + (name: "Asn, Gln", residues: "NQ", fg: "Cyan", bg: "White"), + (name: "Leu, Val, Ile", residues: "LVI", fg: "Green", bg: "White"), + (name: "Pro", residues: "P", fg: "Apricot", bg: "White"), + ), + DNA: ( + (name: "C", residues: "Cc", fg: "Black", bg: "BrewerC"), + (name: "G", residues: "Gg", fg: "White", bg: "BrewerG"), + (name: "A", residues: "Aa", fg: "Black", bg: "BrewerA"), + (name: "T,U", residues: "TtUu", fg: "Black", bg: "BrewerT"), + ), +) + +#let _default-logo-colors = ( + P: ( + D: "Red", E: "Red", + C: "Yellow", M: "Yellow", + K: "Blue", R: "Blue", + S: "Orange", T: "Orange", + F: "MidnightBlue", Y: "MidnightBlue", + N: "Cyan", Q: "Cyan", + G: "LightGray", + L: "Green", V: "Green", I: "Green", + A: "DarkGray", + W: "LightMagenta", + H: "CornflowerBlue", + P: "Apricot", + B: "LightMagenta", Z: "LightMagenta", + ), + N: ( + G: "Black", + A: "Green", + T: "Red", + U: "Red", + C: "Blue", + ), +) + +#let _logo-color-presets = ( + nucleotide: ( + (residues: "G", color: "Black"), + (residues: "A", color: "Green"), + (residues: "TU", color: "Red"), + (residues: "C", color: "Blue"), + ), + rasmol: ( + (residues: "DE", color: "Red"), + (residues: "CM", color: "Yellow"), + (residues: "KR", color: "Blue"), + (residues: "ST", color: "Orange"), + (residues: "FY", color: "MidnightBlue"), + (residues: "NQ", color: "Cyan"), + (residues: "G", color: "LightGray"), + (residues: "LVI", color: "Green"), + (residues: "A", color: "DarkGray"), + (residues: "W", color: "CarnationPink"), + (residues: "H", color: "CornflowerBlue"), + (residues: "P", color: "Apricot"), + (residues: "BZ", color: "LightMagenta"), + ), + chemical: ( + (residues: "DE", color: "Red"), + (residues: "VIL", color: "Black"), + (residues: "AG", color: "Gray"), + (residues: "NQ", color: "Green"), + (residues: "FYW", color: "Brown"), + (residues: "KRH", color: "Blue"), + (residues: "ST", color: "Magenta"), + (residues: "P", color: "Orange"), + (residues: "CM", color: "Yellow"), + ), + hydropathy: ( + (residues: "DE", color: "Red"), + (residues: "KRH", color: "Blue"), + (residues: "YSTGNQC", color: "Yellow"), + (residues: "AFPMWVIL", color: "Green"), + ), + structure: ( + (residues: "DEHKNQR", color: "Orange"), + (residues: "ACGPSTWY", color: "Yellow"), + (residues: "FILMV", color: "Green"), + ), + "standard area": ( + (residues: "G", color: "BrickRed"), + (residues: "AS", color: "Orange"), + (residues: "CP", color: "Yellow"), + (residues: "TDVN", color: "YellowGreen"), + (residues: "IE", color: "PineGreen"), + (residues: "LQHM", color: "SkyBlue"), + (residues: "FK", color: "RoyalPurple"), + (residues: "Y", color: "RedViolet"), + (residues: "RW", color: "Black"), + ), + "accessible area": ( + (residues: "C", color: "BrickRed"), + (residues: "IVG", color: "Orange"), + (residues: "FLMA", color: "Yellow"), + (residues: "WSTH", color: "YellowGreen"), + (residues: "P", color: "PineGreen"), + (residues: "YDN", color: "SkyBlue"), + (residues: "EQ", color: "RoyalPurple"), + (residues: "R", color: "RedViolet"), + (residues: "K", color: "Black"), + ), + hardness: ( + (residues: "ADEGILPQSTV", color: "BlueRed5"), + (residues: "KN", color: "BlueRed20"), + (residues: "R", color: "BlueRed40"), + (residues: "CFH", color: "BlueRed60"), + (residues: "MY", color: "BlueRed80"), + (residues: "W", color: "BlueRed100"), + ), + DNA: ( + (residues: "A", color: "BrewerA"), + (residues: "C", color: "BrewerC"), + (residues: "G", color: "BrewerG"), + (residues: "TU", color: "BrewerT"), + ), +) + +#let _rgb(tuple) = rgb(int(calc.round(tuple.at(0))), int(calc.round(tuple.at(1))), int(calc.round(tuple.at(2)))) + +#let _mix-rgb(a, b, ratio) = ( + int(calc.round(a.at(0) + (b.at(0) - a.at(0)) * ratio)), + int(calc.round(a.at(1) + (b.at(1) - a.at(1)) * ratio)), + int(calc.round(a.at(2) + (b.at(2) - a.at(2)) * ratio)), +) + +#let _color-name(value) = if type(value) == str { value } else { str(value) } + +#let _rgb-components(value, default: "Black") = { + if value == none { + return _color-db.at(default) + } + let key = _color-name(value) + if _color-db.keys().contains(key) { + return _color-db.at(key) + } + let scale-hit = key.matches(regex("^([A-Za-z]+)(\\d+)$")) + if scale-hit.len() > 0 and _scale-db.keys().contains(scale-hit.first().captures.at(0)) { + let level = int(scale-hit.first().captures.at(1)) + let points = _scale-db.at(scale-hit.first().captures.at(0)) + if level <= points.first().at(0) { + return points.first().at(1) + } + if level >= points.last().at(0) { + return points.last().at(1) + } + for idx in range(0, points.len() - 1) { + let left = points.at(idx) + let right = points.at(idx + 1) + if level >= left.at(0) and level <= right.at(0) { + let span = right.at(0) - left.at(0) + let ratio = if span == 0 { 0.0 } else { (level - left.at(0)) / span } + return _mix-rgb(left.at(1), right.at(1), ratio) + } + } + } + _color-db.at(default) +} + +#let resolve-color(value, default: "Black") = { + if value == none { + return _rgb(_color-db.at(default)) + } + if type(value) == color { + return value + } + let key = _color-name(value) + if key.starts-with("#") { + return rgb(key) + } + if key.starts-with("rgb(") { + return rgb(key) + } + let scale-hit = key.matches(regex("^([A-Za-z]+)(\\d+)$")) + if scale-hit.len() > 0 and _scale-db.keys().contains(scale-hit.first().captures.at(0)) { + return scale-color(scale-hit.first().captures.at(0), int(scale-hit.first().captures.at(1))) + } + if _color-db.keys().contains(key) { + return _rgb(_color-db.at(key)) + } + black +} + +#let scale-color(name, value) = { + let clamped = calc.max(0, calc.min(100, value)) + let key = _color-name(name) + if key == "BlackWhite" or key == "WhiteBlack" { + let scale-key = key + str(calc.round(clamped / 5) * 5) + return resolve-color(scale-key, default: "Black") + } + if not _scale-db.keys().contains(key) { + return resolve-color("Gray50") + } + let points = _scale-db.at(key) + if clamped <= points.first().at(0) { + return _rgb(points.first().at(1)) + } + if clamped >= points.last().at(0) { + return _rgb(points.last().at(1)) + } + for idx in range(0, points.len() - 1) { + let left = points.at(idx) + let right = points.at(idx + 1) + if clamped >= left.at(0) and clamped <= right.at(0) { + let span = right.at(0) - left.at(0) + let ratio = if span == 0 { 0.0 } else { (clamped - left.at(0)) / span } + return _rgb(_mix-rgb(left.at(1), right.at(1), ratio)) + } + } + _rgb(points.last().at(1)) +} diff --git a/packages/preview/typshade/0.1.3/internal/model/parser.typ b/packages/preview/typshade/0.1.3/internal/model/parser.typ new file mode 100644 index 0000000000..6a55283130 --- /dev/null +++ b/packages/preview/typshade/0.1.3/internal/model/parser.typ @@ -0,0 +1,519 @@ +// Copyright (C) 2026 Eito Yoneyama +// SPDX-License-Identifier: GPL-2.0 + +#let _translate-case(text, from, to) = { + let out = "" + for ch in text.clusters() { + let idx = from.position(ch) + out += if idx == none { ch } else { to.slice(idx, idx + 1) } + } + out +} + +#let _upper(text) = { + let lower = "abcdefghijklmnopqrstuvwxyz" + let upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + _translate-case(str(text), lower, upper) +} + +#let _lower(text) = { + let lower = "abcdefghijklmnopqrstuvwxyz" + let upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + _translate-case(str(text), upper, lower) +} + +#let _split-lines(text) = text.replace("\r\n", "\n").replace("\r", "\n").split("\n") + +#let _v15-or-later() = sys.version >= version(0, 15, 0) + +#let _source-is-path(source) = { + if _v15-or-later() { + type(source) == path + } else { + false + } +} + +#let _looks-like-source-text(source) = { + let text = str(source) + let trimmed = text.trim() + trimmed == "" or text.contains("\n") or trimmed.starts-with(">") or trimmed.starts-with("CLUSTAL") or trimmed.starts-with("MUSCLE") or trimmed.starts-with("ATOM") or trimmed.starts-with("HETATM") or text.contains(" MSF: ") or text.contains("!!AA_MULTIPLE_ALIGNMENT") or text.contains("!!NA_MULTIPLE_ALIGNMENT") or trimmed.matches(regex("^\\S+\\s+[A-Za-z\\-\\.]+$")).len() > 0 +} + +#let _source-text(source) = { + if type(source) == bytes { + str(source) + } else if _source-is-path(source) { + str(read(source, encoding: none)) + } else { + assert( + type(source) == str and _looks-like-source-text(source), + message: "typshade: source must be alignment text, bytes, or path(...); use read(..., encoding: none) or path(...) for files", + ) + source + } +} + +#let _strip-empty(lines) = { + let out = () + for line in lines { + if line != "" { + out.push(line) + } + } + out +} + +#let _chars(text) = { + let out = () + for ch in str(text).clusters() { + out.push(ch) + } + out +} + +#let _repeat(value, times) = { + let out = () + for _ in range(0, times) { + out.push(value) + } + out +} + +#let _array-fill(length, value) = { + let out = () + for _ in range(0, length) { + out.push(if type(value) == dictionary { value + (:) } else { value }) + } + out +} + +#let _clone-array(items) = { + let out = () + for item in items { + out.push(item) + } + out +} + +#let _guess-seq-type(sequences) = { + let dna = "ACGTUNRYKMWSBDHV.-" + let protein = "ABCDEFGHIKLMNPQRSTVWXYZOUJ.-" + let dna-only = 0 + let protein-only = 0 + for seq in sequences { + for ch in _chars(_upper(seq.at("aligned"))) { + if protein.contains(ch) { + protein-only += 1 + } + if dna.contains(ch) { + dna-only += 1 + } + } + } + if sequences.len() == 0 or (dna-only > 0 and protein-only == dna-only) { + "N" + } else { + "P" + } +} + +#let _build-sequence(name, aligned, metadata) = { + let positions = () + let raw = "" + let pos = 0 + for ch in _chars(aligned) { + if ch == "." or ch == "-" { + positions.push(none) + } else { + pos += 1 + raw += ch + positions.push(pos) + } + } + ( + name: name, + aligned: aligned, + raw: raw, + positions: positions, + length: pos, + metadata: metadata, + ) +} + +#let _validated-alignment(format, sequences, seq-type, name: "alignment") = { + assert(sequences.len() > 0, message: "typshade: " + format + " alignment is empty") + let columns = sequences.first().at("aligned").len() + for seq in sequences { + let length = seq.at("aligned").len() + assert( + length == columns, + message: "typshade: " + format + " alignment has inconsistent column length for sequence `" + seq.at("name") + "`: expected " + str(columns) + ", got " + str(length), + ) + } + ( + format: format, + name: name, + seq-type: seq-type, + columns: columns, + sequences: sequences, + ) +} + +#let parse-msf(text) = { + let lines = _split-lines(text) + let body = false + let blocks = (:) + let ignored = () + let declared-type = none + for line in lines { + let trimmed = line.trim() + if trimmed == "//" { + body = true + continue + } + if not body { + let ignored-hit = trimmed.matches(regex("^!Name:\\s+(\\S+)")) + if ignored-hit.len() > 0 { + ignored.push(ignored-hit.first().captures.at(0)) + } + let type-hit = trimmed.matches(regex("Type:\\s*([PN])")) + if type-hit.len() > 0 { + declared-type = type-hit.first().captures.at(0) + } + continue + } + if trimmed == "" { + continue + } + let hit = trimmed.matches(regex("^(\\S+)\\s+(.+)$")) + if hit.len() == 0 { + continue + } + let name = hit.first().captures.at(0) + if name.matches(regex("^\\d+$")).len() > 0 { + continue + } + let fragment = hit.first().captures.at(1).replace(" ", "") + if not blocks.keys().contains(name) { + blocks.insert(name, "") + } + blocks.insert(name, blocks.at(name) + fragment) + } + let sequences = () + for name in blocks.keys() { + if not ignored.contains(name) { + sequences.push(_build-sequence(name, blocks.at(name), (:))) + } + } + _validated-alignment( + "MSF", + sequences, + if declared-type == none { _guess-seq-type(sequences) } else { declared-type }, + ) +} + +#let parse-aln(text) = { + let lines = _split-lines(text) + let pieces = (:) + for line in lines { + if line.trim() == "" or line.starts-with("CLUSTAL") or line.starts-with("MUSCLE") or line.starts-with(" ") { + continue + } + let matches = line.matches(regex("^(\\S+)\\s+([A-Za-z\\-\\.]+)")) + if matches.len() == 0 { + continue + } + let hit = matches.first() + let name = hit.captures.at(0) + let fragment = hit.captures.at(1) + if not pieces.keys().contains(name) { + pieces.insert(name, "") + } + pieces.insert(name, pieces.at(name) + fragment) + } + let sequences = () + for name in pieces.keys() { + sequences.push(_build-sequence(name, pieces.at(name), (:))) + } + _validated-alignment("ALN", sequences, _guess-seq-type(sequences)) +} + +#let parse-fasta(text) = { + let lines = _split-lines(text) + let sequences = () + let current-name = none + let current-seq = "" + for line in lines { + if line.starts-with(">") { + if current-name != none { + sequences.push(_build-sequence(current-name, current-seq, (:))) + } + let label = line.slice(1).trim() + current-name = if label == "" { "seq" + str(sequences.len() + 1) } else { label.split(" ").first() } + current-seq = "" + } else if line.trim() != "" { + current-seq += line.trim() + } + } + if current-name != none { + sequences.push(_build-sequence(current-name, current-seq, (:))) + } + _validated-alignment("FASTA", sequences, _guess-seq-type(sequences)) +} + +#let _detected-format(format, text) = { + if format == auto { + if text.trim().starts-with(">") { + return "FASTA" + } + if text.contains(" MSF: ") { + return "MSF" + } + return "ALN" + } + let key = _upper(str(format)) + if key == "AUTO" { + _detected-format(auto, text) + } else if key == "FASTA" or key == "FA" or key == "FAS" { + "FASTA" + } else if key == "MSF" { + "MSF" + } else if key == "ALN" or key == "CLUSTAL" or key == "MUSCLE" { + "ALN" + } else { + assert( + false, + message: "typshade: unknown alignment format `" + str(format) + "`; expected auto, fasta, msf, or aln", + ) + } +} + +#let read-alignment(source, format: auto) = { + let text = _source-text(source) + let detected = _detected-format(format, text) + if detected == "MSF" { + parse-msf(text) + } else if detected == "FASTA" { + parse-fasta(text) + } else { + parse-aln(text) + } +} + +#let read-tcoffee(source) = { + let data = (:) + let lines = _split-lines(_source-text(source)) + for line in lines { + let trimmed = line.trim() + let matches = trimmed.matches(regex("^(\\S+)\\s+\\d+\\s+([A-Za-z0-9\\-]+)\\s+\\d+$")) + if matches.len() == 0 { + continue + } + let name = matches.first().captures.at(0) + let fragment = matches.first().captures.at(1) + let scores = if data.keys().contains(name) { data.at(name) } else { () } + for ch in _chars(fragment) { + if ch == "-" { + scores.push(none) + } else if ch.matches(regex("\\d")).len() > 0 { + scores.push(int(ch) * 10) + } else { + scores.push(0) + } + } + data.insert(name, scores) + } + data +} + +#let _run-lengths(chars, allowed) = { + let regions = () + let active = false + let start = 0 + for idx in range(0, chars.len()) { + let hit = allowed.contains(chars.at(idx)) + if hit and not active { + active = true + start = idx + 1 + } + if active and (not hit or idx == chars.len() - 1) { + let stop = if hit and idx == chars.len() - 1 { idx + 1 } else { idx } + regions.push((start, stop)) + active = false + } + } + regions +} + +#let read-hmmtop(source, sequence: none) = { + let text = _source-text(source) + if text.contains("Transmembrane helices:") { + let name = text.matches(regex("Protein:\\s*(\\S+)")).first().captures.at(0) + let orientation = text.matches(regex("N-terminus:\\s*(\\S+)")).first().captures.at(0) + let spans-line = text.matches(regex("Transmembrane helices:\\s*([0-9\\- ]+)")).first().captures.at(0) + let spans = () + for token in spans-line.split(" ") { + if token.trim() == "" { + continue + } + let hit = token.matches(regex("^(\\d+)-(\\d+)$")).first() + spans.push((int(hit.captures.at(0)), int(hit.captures.at(1)))) + } + return (name: name, orientation: orientation, spans: spans) + } + let lines = _split-lines(text) + for line in lines { + let trimmed = line.trim() + if not trimmed.starts-with(">HP:") { + continue + } + let hit = trimmed.matches(regex("^>HP:\\s*(\\d+)\\s+(\\S+)\\s+(\\S+)\\s+(\\d+)\\s+(.+)$")).first() + let name = hit.captures.at(1) + if sequence != none and name != str(sequence) { + continue + } + let orientation = hit.captures.at(2) + let values = _strip-empty(hit.captures.at(4).split(" ")) + let spans = () + let idx = 0 + while idx + 1 < values.len() { + spans.push((int(values.at(idx)), int(values.at(idx + 1)))) + idx += 2 + } + return (name: name, orientation: orientation, spans: spans) + } + (name: "", orientation: "IN", spans: ()) +} + +#let read-phd-topology(source) = { + let runs = "" + for line in _split-lines(_source-text(source)) { + let matches = line.matches(regex("^\\s*PHDThtm\\s*\\|([^|]+)\\|")) + if matches.len() > 0 { + runs += matches.first().captures.at(0).replace(" ", "") + } + } + ( + topology: runs, + spans: _run-lengths(_chars(runs), "T"), + internal: _run-lengths(_chars(runs), "iI"), + external: _run-lengths(_chars(runs), "oO"), + ) +} + +#let read-phd-secondary(source) = { + let runs = "" + for line in _split-lines(_source-text(source)) { + let matches = line.matches(regex("^\\s*PHD sec\\s*\\|([^|]+)\\|")) + if matches.len() > 0 { + runs += matches.first().captures.at(0) + } + } + ( + sequence: runs, + alpha: _run-lengths(_chars(runs), "H"), + beta: _run-lengths(_chars(runs), "E"), + turn: _run-lengths(_chars(runs), "T"), + ) +} + +#let _runs-from-entries(entries, allowed) = { + let regions = () + let active = false + let start = 0 + let last = 0 + for entry in entries { + let pos = entry.at("pos") + let code = entry.at("code") + let hit = allowed.contains(code) + let contiguous = active and pos == last + 1 + if hit and (not active or not contiguous) { + if active { + regions.push((start, last)) + } + active = true + start = pos + } else if not hit and active { + regions.push((start, last)) + active = false + } + last = pos + } + if active { + regions.push((start, last)) + } + regions +} + +#let read-dssp(source, use-second-column: true) = { + let entries = () + let started = false + for line in _split-lines(_source-text(source)) { + if not started { + if line.contains("RESIDUE AA STRUCTURE") { + started = true + } + continue + } + if line.trim() == "" or line.len() < 17 { + continue + } + let first-field = line.slice(0, calc.min(5, line.len())).trim() + let second-field = line.slice(calc.min(5, line.len()), calc.min(10, line.len())).trim() + let aa = line.slice(calc.min(13, line.len()), calc.min(14, line.len())).trim() + if aa == "" or aa == "!" { + continue + } + let code = line.slice(calc.min(16, line.len()), calc.min(17, line.len())).trim() + let pos = if use-second-column and second-field != "" { + int(second-field) + } else if first-field != "" { + int(first-field) + } else { + entries.len() + 1 + } + entries.push((pos: pos, code: if code == "" { "C" } else { code })) + } + ( + sequence: entries.map(entry => entry.at("code")).join(""), + alpha: _runs-from-entries(entries, "H"), + "3-10": _runs-from-entries(entries, "G"), + pi: _runs-from-entries(entries, "I"), + beta: _runs-from-entries(entries, "E"), + bridge: _runs-from-entries(entries, "B"), + turn: _runs-from-entries(entries, "T"), + bend: _runs-from-entries(entries, "S"), + ) +} + +#let read-stride(source) = { + let entries = () + for line in _split-lines(_source-text(source)) { + let trimmed = line.trim() + if not trimmed.starts-with("ASG") { + continue + } + let hit = trimmed.matches(regex("^ASG\\s+\\S+\\s+\\S+\\s+(-?\\d+)\\s+(-?\\d+)\\s+([A-Z])")) + if hit.len() > 0 { + let captures = hit.first().captures + entries.push((pos: int(captures.at(1)), code: captures.at(2))) + continue + } + let fields = _strip-empty(trimmed.split(" ")) + if fields.len() >= 6 { + let pos = int(fields.at(4)) + let code = fields.at(5) + entries.push((pos: pos, code: code)) + } + } + ( + sequence: entries.map(entry => entry.at("code")).join(""), + alpha: _runs-from-entries(entries, "H"), + "3-10": _runs-from-entries(entries, "G"), + pi: _runs-from-entries(entries, "I"), + beta: _runs-from-entries(entries, "E"), + bridge: _runs-from-entries(entries, "B"), + turn: _runs-from-entries(entries, "T"), + ) +} diff --git a/packages/preview/typshade/0.1.3/internal/model/pdb.typ b/packages/preview/typshade/0.1.3/internal/model/pdb.typ new file mode 100644 index 0000000000..cd87131b4e --- /dev/null +++ b/packages/preview/typshade/0.1.3/internal/model/pdb.typ @@ -0,0 +1,210 @@ +// Copyright (C) 2026 Eito Yoneyama +// SPDX-License-Identifier: GPL-2.0 + +#import "parser.typ": _source-text, _split-lines, _upper + +#let _field(line, start, stop) = if line.len() >= stop { + line.slice(start, stop).trim() +} else { + "" +} + +#let _vec-sub(a, b) = ( + x: a.at("x") - b.at("x"), + y: a.at("y") - b.at("y"), + z: a.at("z") - b.at("z"), +) + +#let _vec-dot(a, b) = a.at("x") * b.at("x") + a.at("y") * b.at("y") + a.at("z") * b.at("z") +#let _vec-len2(a) = _vec-dot(a, a) + +#let _vec-cross(a, b) = ( + x: a.at("y") * b.at("z") - a.at("z") * b.at("y"), + y: a.at("z") * b.at("x") - a.at("x") * b.at("z"), + z: a.at("x") * b.at("y") - a.at("y") * b.at("x"), +) + +#let _read-pdb-atoms(source) = { + let atoms = () + for line in _split-lines(_source-text(source)) { + if not (line.starts-with("ATOM") or line.starts-with("HETATM")) or line.len() < 54 { + continue + } + let res = _field(line, 22, 26) + let x = _field(line, 30, 38) + let y = _field(line, 38, 46) + let z = _field(line, 46, 54) + if res == "" or x == "" or y == "" or z == "" { + continue + } + atoms.push(( + atom: _upper(_field(line, 12, 16)), + residue: int(res), + x: float(x), + y: float(y), + z: float(z), + )) + } + atoms +} + +#let _atoms-for-residue(atoms, residue) = { + let out = () + for atom in atoms { + if atom.at("residue") == residue { + out.push(atom) + } + } + out +} + +#let _atom-point(atom) = (x: atom.at("x"), y: atom.at("y"), z: atom.at("z")) + +#let _anchor-point(atoms, residue, atom-kind) = { + let residue-atoms = _atoms-for-residue(atoms, residue) + if residue-atoms.len() == 0 { + return none + } + let ca = none + for atom in residue-atoms { + if atom.at("atom") == "CA" { + ca = atom + } + } + if _upper(str(atom-kind)) == "CA" and ca != none { + return _atom-point(ca) + } + let backbone = ("N", "CA", "C", "O") + let best = none + let best-distance = -1.0 + let origin = if ca == none { residue-atoms.first() } else { ca } + for atom in residue-atoms { + if backbone.contains(atom.at("atom")) and residue-atoms.len() > backbone.len() { + continue + } + let distance = _vec-len2(_vec-sub(_atom-point(atom), _atom-point(origin))) + if distance > best-distance { + best = atom + best-distance = distance + } + } + if best == none { _atom-point(residue-atoms.first()) } else { _atom-point(best) } +} + +#let _parse-anchor(text) = { + let hit = str(text).trim().matches(regex("^(-?\\d+)(?:\\[([^\\]]+)\\])?$")) + if hit.len() == 0 { + return none + } + let captures = hit.first().captures + (residue: int(captures.at(0)), atom: captures.at(1, default: "side")) +} + +#let _parse-pdb-selection(selection) = { + if type(selection) == dictionary and selection.at("kind", default: none) == "pdb-selection" { + return selection + } + let hit = str(selection).trim().matches(regex("^(point|line|plane)(?:\\[([^\\]]+)\\])?:(.+)$")) + if hit.len() == 0 { + return none + } + let captures = hit.first().captures + let kind = captures.at(0) + let distance = if captures.at(1, default: "") == "" { 1.0 } else { float(captures.at(1)) } + let parts = captures.at(2).split(",").map(part => part.trim()).filter(part => part != "") + if parts.len() < 2 { + return none + } + let anchors = () + for part in parts.slice(1) { + let anchor = _parse-anchor(part) + if anchor != none { + anchors.push(anchor) + } + } + (kind: "pdb-selection", shape: kind, distance: distance, source: parts.first(), anchors: anchors) +} + +#let _distance2-to-segment(point, a, b) = { + let ab = _vec-sub(b, a) + let denom = _vec-len2(ab) + if denom == 0 { + return _vec-len2(_vec-sub(point, a)) + } + let t = calc.max(0.0, calc.min(1.0, _vec-dot(_vec-sub(point, a), ab) / denom)) + let projected = (x: a.at("x") + ab.at("x") * t, y: a.at("y") + ab.at("y") * t, z: a.at("z") + ab.at("z") * t) + _vec-len2(_vec-sub(point, projected)) +} + +#let _distance2-to-plane(point, a, b, c) = { + let normal = _vec-cross(_vec-sub(b, a), _vec-sub(c, a)) + let denom = _vec-len2(normal) + if denom == 0 { + return _distance2-to-segment(point, a, b) + } + let numerator = _vec-dot(_vec-sub(point, a), normal) + numerator * numerator / denom +} + +#let _residue-numbers(atoms) = { + let seen = (:) + let out = () + for atom in atoms { + let key = str(atom.at("residue")) + if not seen.keys().contains(key) { + seen.insert(key, true) + out.push(atom.at("residue")) + } + } + out.sorted() +} + +#let _pdb-selection-positions(selection) = { + let parsed = _parse-pdb-selection(selection) + if parsed == none { + return none + } + let atoms = _read-pdb-atoms(parsed.at("source")) + let anchors = () + for anchor in parsed.at("anchors") { + let point = _anchor-point(atoms, anchor.at("residue"), anchor.at("atom")) + if point != none { + anchors.push(point) + } + } + let shape = parsed.at("shape", default: parsed.at("kind")) + let required = if shape == "point" { 1 } else if shape == "line" { 2 } else { 3 } + if anchors.len() < required { + return () + } + let max-distance2 = parsed.at("distance") * parsed.at("distance") + let out = () + for residue in _residue-numbers(atoms) { + let selected = false + for atom in _atoms-for-residue(atoms, residue) { + let point = _atom-point(atom) + let distance2 = if shape == "point" { + _vec-len2(_vec-sub(point, anchors.at(0))) + } else if shape == "line" { + _distance2-to-segment(point, anchors.at(0), anchors.at(1)) + } else { + _distance2-to-plane(point, anchors.at(0), anchors.at(1), anchors.at(2)) + } + if distance2 <= max-distance2 { + selected = true + } + } + if selected { + out.push(residue) + } + } + out +} + +#let pdb-selection-list(selection) = { + let positions = _pdb-selection-positions(selection) + if positions == none { + return str(selection) + } + positions.map(pos => str(pos)).join(",") +} diff --git a/packages/preview/typshade/0.1.3/internal/model/text-style.typ b/packages/preview/typshade/0.1.3/internal/model/text-style.typ new file mode 100644 index 0000000000..806f2b51e2 --- /dev/null +++ b/packages/preview/typshade/0.1.3/internal/model/text-style.typ @@ -0,0 +1,132 @@ +// Copyright (C) 2026 Eito Yoneyama +// SPDX-License-Identifier: GPL-2.0 + +#import "parser.typ": _upper + +#let _text-style-targets = ( + "residues", + "numbering", + "names", + "feature-text-labels", + "feature-style-labels", + "features", + "feature-styles", + "legend", + "ruler", + "ruler-label", +) + +#let _default-text-styles = ( + "residues": (family: "mono", weight: "regular", style: "normal", size: "normal"), + "numbering": (family: "mono", weight: "regular", style: "normal", size: "normal"), + "names": (family: "mono", weight: "regular", style: "normal", size: "normal"), + "feature-text-labels": (family: "mono", weight: "regular", style: "normal", size: "normal"), + "feature-style-labels": (family: "mono", weight: "regular", style: "normal", size: "normal"), + "features": (family: "serif", weight: "regular", style: "italic", size: "normal"), + "feature-styles": (family: "mono", weight: "regular", style: "normal", size: "normal"), + "legend": (family: "mono", weight: "regular", style: "normal", size: "normal"), + "ruler": (family: "sans", weight: "regular", style: "normal", size: "normal"), + "ruler-label": (family: "sans", weight: "regular", style: "normal", size: "normal"), +) + +#let _font-family(config, family) = { + if family == "mono" { + return config.at("font") + } + if family == "sans" { + return config.at("font-families").at("sans") + } + if family == "serif" { + return config.at("font-families").at("serif") + } + family +} + +#let _size-factor(size) = { + if type(size) != str { + return size + } + if size == "tiny" { + 0.55 + } else if size == "x-small" { + 0.7 + } else if size == "smaller" { + 0.8 + } else if size == "small" { + 0.9 + } else if size == "normal" { + 1.0 + } else if size == "large" { + 1.2 + } else if size == "x-large" { + 1.44 + } else if size == "xx-large" { + 1.72 + } else if size == "huge" { + 2.05 + } else if size == "x-huge" { + 2.45 + } else { + 1.0 + } +} + +#let _font-size(config, size) = { + if type(size) == str { + config.at("font-size") * _size-factor(size) + } else { + size + } +} + +#let _target-list(target) = if target == "all" { + _text-style-targets +} else if type(target) == str { + (target,) +} else { + target +} + +#let _set-text-style(config, target, key, value) = { + for name in _target-list(target) { + if config.at("text-styles").keys().contains(name) { + config.at("text-styles").at(name).insert(key, value) + } + } +} + +#let _text-style(config, target) = { + let base = _default-text-styles.at(target, default: _default-text-styles.at("residues")) + let overrides = config.at("text-styles").at(target, default: (:)) + let family = overrides.at("family", default: base.at("family")) + let weight = overrides.at("weight", default: base.at("weight")) + let style = overrides.at("style", default: base.at("style")) + let size = overrides.at("size", default: base.at("size")) + ( + font: _font-family(config, family), + size: _font-size(config, size), + weight: if weight == "bold" { "bold" } else { "regular" }, + style: if style == "italic" or style == "oblique" { "italic" } else { "normal" }, + smallcaps: style == "small-caps", + ) +} + +#let _text-params(config, target, fill: black, style: auto, size: auto) = { + let resolved = _text-style(config, target) + ( + font: resolved.at("font"), + size: if size == auto { resolved.at("size") } else { size }, + weight: resolved.at("weight"), + style: if style == auto { resolved.at("style") } else { style }, + fill: fill, + ) +} + +#let _text-string(config, target, value) = { + let text = str(value) + if _text-style(config, target).at("smallcaps") { + _upper(text) + } else { + text + } +} diff --git a/packages/preview/typshade/0.1.3/internal/render/alignment.typ b/packages/preview/typshade/0.1.3/internal/render/alignment.typ new file mode 100644 index 0000000000..1b261ba1a0 --- /dev/null +++ b/packages/preview/typshade/0.1.3/internal/render/alignment.typ @@ -0,0 +1,1280 @@ +// Copyright (C) 2026 Eito Yoneyama +// SPDX-License-Identifier: GPL-2.0 + +#import "../engine/config.typ": _apply-command, _default-config +#import "features.typ": _bottom-feature-slots, _feature-rows, _ruler-rows, _top-feature-slots +#import "../engine/layout.typ": _empty-cell, _selection-columns, _sorted-unique +#import "../model/logo.typ": _resolve-sequence +#import "logos.typ": _legend-block, _logo-block +#import "../model/palette.typ": resolve-color, scale-color +#import "../model/parser.typ": _array-fill, _chars, _lower, _upper, read-alignment +#import "../model/text-style.typ": _font-size, _text-params, _text-string + +#let _display-columns(alignment, config) = { + let selected = () + for command in config.at("sequence-windows") { + let seq = alignment.at("sequences").at(_resolve-sequence(alignment, command.at("sequence"))) + for col in _selection-columns(seq, command.at("selection"), alignment: alignment) { + selected.push(col) + } + } + if selected.len() == 0 { + selected = range(0, alignment.at("columns")) + } + let columns = _sorted-unique(selected) + if not config.at("hide-allmatch-positions") { + return columns + } + let out = () + for col in columns { + let info = _style-for-column(alignment, config, col) + if info.at("consensus-score") < config.at("allmatch-threshold") { + out.push(col) + } + } + out +} + +#let _residue-group(char, seq-type, config) = { + let groups = if seq-type == "N" { config.at("dna-groups") } else { config.at("pep-groups") } + for (idx, group) in groups.enumerate() { + if group.contains(char) { + return idx + } + } + none +} + +#let _is-similar(residue, consensus, seq-type, config) = { + if residue == consensus { + return true + } + let sims = if seq-type == "N" { config.at("dna-sims") } else { config.at("pep-sims") } + if sims.keys().contains(consensus) { + return sims.at(consensus).contains(residue) + } + false +} + +#let _weight-order = ("C", "S", "T", "P", "A", "G", "N", "D", "E", "Q", "H", "R", "K", "M", "I", "L", "V", "F", "Y", "W") + +#let _weight-index(value) = { + for (idx, item) in _weight-order.enumerate() { + if item == value { + return idx + } + } + none +} + +#let _structural-rows = ( + C: (10, 6, 3, 3, 3, 5, 3, 1, 0, 1, 3, 3, 0, 3, 3, 3, 3, 5, 5, 5), + S: (6, 10, 8, 6, 8, 8, 8, 6, 5, 5, 5, 5, 5, 3, 3, 3, 6, 5, 5, 3), + T: (3, 8, 10, 6, 8, 6, 6, 5, 5, 5, 3, 5, 6, 5, 5, 3, 6, 3, 3, 1), + P: (3, 6, 6, 10, 8, 6, 3, 5, 5, 5, 5, 5, 3, 3, 3, 5, 6, 5, 3, 3), + A: (3, 8, 8, 8, 10, 8, 5, 6, 6, 5, 3, 3, 5, 5, 3, 3, 8, 5, 3, 3), + G: (5, 8, 6, 6, 8, 10, 5, 6, 6, 3, 1, 5, 3, 1, 3, 3, 6, 3, 3, 5), + N: (3, 8, 6, 3, 5, 5, 10, 8, 6, 5, 6, 5, 6, 1, 3, 1, 3, 3, 5, 0), + D: (1, 6, 5, 5, 6, 6, 8, 10, 8, 6, 5, 3, 5, 3, 1, 1, 5, 1, 3, 0), + E: (0, 5, 5, 5, 6, 6, 6, 8, 10, 6, 3, 5, 6, 3, 1, 1, 6, 3, 1, 1), + Q: (1, 5, 5, 5, 5, 3, 5, 6, 6, 10, 6, 5, 6, 3, 1, 3, 3, 1, 3, 1), + H: (3, 5, 3, 5, 3, 1, 6, 5, 3, 6, 10, 6, 5, 3, 3, 5, 1, 3, 5, 1), + R: (3, 5, 5, 5, 3, 5, 5, 3, 5, 5, 6, 10, 8, 3, 3, 3, 3, 1, 1, 3), + K: (0, 5, 6, 3, 5, 3, 6, 5, 6, 6, 5, 8, 10, 3, 3, 3, 5, 1, 1, 1), + M: (3, 5, 5, 3, 5, 1, 1, 3, 3, 3, 3, 3, 3, 10, 6, 8, 6, 5, 3, 5), + I: (3, 3, 5, 3, 3, 3, 3, 1, 1, 1, 3, 3, 3, 6, 10, 8, 3, 6, 5, 5), + L: (3, 3, 3, 5, 3, 3, 1, 1, 1, 3, 5, 3, 3, 8, 8, 10, 3, 6, 5, 6), + V: (3, 6, 6, 6, 8, 6, 3, 5, 6, 3, 1, 3, 5, 6, 3, 3, 10, 6, 5, 5), + F: (5, 5, 3, 5, 5, 3, 3, 1, 3, 1, 3, 1, 1, 5, 6, 6, 6, 10, 8, 5), + Y: (5, 5, 3, 3, 3, 3, 5, 3, 1, 3, 5, 1, 1, 3, 5, 5, 5, 8, 10, 5), + W: (5, 3, 1, 3, 3, 5, 0, 0, 1, 1, 1, 3, 1, 5, 5, 6, 5, 5, 5, 10), +) + +#let _pam250-rows = ( + C: (4, 0, -2, -3, -2, -3, -4, 2, -5, -5, -3, -4, -5, -5, -2, -6, -2, -4, 0, -8), + S: (0, 3, 1, 1, 1, 1, 1, 0, 0, -1, -1, 0, 0, -2, -1, -3, -1, -3, -3, -2), + T: (-2, 1, 3, 0, 1, 0, 0, 0, 0, -1, -1, -1, 0, -1, 0, -2, 0, -2, -3, -5), + P: (-3, 1, 0, 6, 1, -1, -1, -1, -1, 0, 0, 0, -1, -2, -2, -3, -1, -5, -5, -6), + A: (-2, 1, 1, 1, 2, 1, 0, 0, 0, 0, -1, -2, -1, -1, -1, -2, 0, -4, -3, -6), + G: (-3, 1, 0, -1, 1, 5, 0, 1, 0, -1, -2, -3, -2, -3, -3, -4, -1, -5, -5, -7), + N: (-4, 1, 0, -1, 0, 0, 2, 2, 1, 1, 2, 0, 1, -2, -2, -3, -2, -4, -2, -4), + D: (-5, 0, 0, -1, 0, 1, 2, 4, 3, 2, 1, -1, 0, -3, -2, -4, -2, -6, -4, -7), + E: (-5, 0, 0, -1, 0, 0, 1, 3, 4, 2, 1, -1, 0, -2, -2, -3, -2, -5, -4, -7), + Q: (-5, -1, -1, 0, 0, -1, 1, 2, 2, 4, 3, 1, 1, -1, -2, -2, -2, -5, -4, -5), + H: (-3, -1, -1, 0, -1, -2, 2, 1, 1, 3, 6, 2, 0, -2, -2, -2, -2, -2, -5, -7), + R: (-4, 0, -1, 0, -2, -3, 0, -1, -1, 1, 2, 6, 3, 0, -2, -3, -2, -4, -4, 2), + K: (-5, 0, 0, -1, -1, -2, 1, 0, 0, 1, 0, 3, 5, 0, -2, -3, -2, -5, -4, -3), + M: (-5, -2, -1, -2, -1, -3, -2, -3, -2, -1, -2, 0, 0, 6, 2, 4, 2, 0, -2, -4), + I: (-2, -1, 0, -2, -1, -3, -2, -2, -2, -2, -2, -2, -2, 2, 5, 2, 4, 1, -1, -5), + L: (-6, -3, -2, -3, -2, -4, -3, -4, -3, -2, -2, -3, -3, 4, 2, 6, 2, 2, -1, -2), + V: (-2, -1, 0, -1, 0, -1, -2, -2, -2, -2, -2, -2, -2, 2, 4, 2, 4, -1, -2, -6), + F: (-4, -3, -2, -5, -4, -5, -4, -6, -5, -5, -2, -4, -5, 0, 1, 2, -1, 9, 7, 0), + Y: (0, -3, -3, -5, -3, -5, -2, -4, -4, -4, 0, -4, -4, -2, -1, -1, -2, 7, 10, 0), + W: (-8, -2, -5, -6, -6, -7, -4, -7, -7, -5, -3, 2, -3, -4, -5, -2, -6, 0, 0, 17), +) + +#let _pam100-rows = ( + C: (14, -1, -5, -6, -5, -8, -8, -11, -11, -11, -6, -6, -11, -11, -5, -12, -4, -10, -2, -13), + S: (-1, 6, 2, 1, 2, 1, 2, -1, -2, -3, -4, -1, -2, -4, -4, -7, -4, -5, -6, -4), + T: (-5, 2, 7, -1, 2, -3, 0, -2, -3, -3, -5, -4, -1, -2, -1, -5, -1, -6, -6, -10), + P: (-6, 1, -1, 10, 1, -3, -3, -4, -3, -1, -2, -2, -4, -6, -6, -5, -4, -9, -11, -11), + A: (-5, 2, 2, 1, 6, 1, -1, -1, 0, -2, -5, -5, -4, -3, -3, -5, 0, -7, -6, -11), + G: (-8, 1, -3, -3, 1, 8, -1, -1, -2, -5, -7, -8, -5, -8, -7, -8, -4, -8, -11, -13), + N: (-8, 2, 0, -3, -1, -1, 7, 4, 1, -1, 2, -3, 1, -5, -4, -6, -5, -6, -3, -8), + D: (-11, -1, -2, -4, -1, -1, 4, 8, 5, 1, -1, -6, -2, -8, -6, -9, -6, -11, -9, -13), + E: (-11, -2, -3, -3, 0, -2, 1, 5, 8, 4, -2, -5, -2, -6, -5, -7, -5, -11, -7, -14), + Q: (-11, -3, -3, -1, -2, -5, -1, 1, 4, 9, 4, 1, -1, -2, -5, -3, -5, -10, -9, -11), + H: (-6, -4, -5, -2, -5, -7, 2, -1, -2, 4, 11, 1, -3, -7, -7, -5, -6, -4, -1, -7), + R: (-6, -1, -4, -2, -5, -8, -3, -6, -5, 1, 1, 10, 3, -2, -4, -7, -6, -7, -10, 1), + K: (-11, -2, -1, -4, -4, -5, 1, -2, -2, -1, -3, 3, 8, 1, -4, -6, -6, -11, -10, -9), + M: (-11, -4, -2, -6, -3, -8, -5, -8, -6, -2, -7, -2, 1, 13, 2, 4, 1, -2, -8, -11), + I: (-5, -4, -1, -6, -3, -7, -4, -6, -5, -5, -7, -4, -4, 2, 9, 2, 5, 0, -4, -12), + L: (-12, -7, -5, -5, -5, -8, -6, -9, -7, -3, -5, -7, -6, 4, 2, 9, 1, 0, -5, -7), + V: (-4, -4, -1, -4, 0, -4, -5, -6, -5, -5, -6, -6, -6, 1, 5, 1, 8, -5, -6, -14), + F: (-10, -5, -6, -9, -7, -8, -6, -11, -11, -10, -4, -7, -11, -2, 0, 0, -5, 12, 6, -2), + Y: (-2, -6, -6, -11, -6, -11, -3, -9, -7, -9, -1, -10, -10, -8, -4, -5, -6, 6, 13, -2), + W: (-13, -4, -10, -11, -11, -13, -8, -13, -14, -11, -7, 1, -9, -11, -12, -7, -14, -2, -2, 19), +) + +#let _blosum62-rows = ( + C: (9, -1, -1, -3, 0, -3, -3, -3, -4, -3, -3, -3, -3, -1, -1, -1, -1, -2, -2, -2), + S: (-1, 4, 1, -1, 1, 0, 1, 0, 0, 0, -1, -1, 0, -1, -2, -2, -2, -2, -2, -3), + T: (-1, 1, 4, 1, -1, 1, 0, 1, 0, 0, 0, -1, 0, -1, -2, -2, -2, -2, -2, -3), + P: (-3, -1, 1, 7, -1, -2, -1, -1, -1, -1, -2, -2, -1, -2, -3, -3, -2, -4, -3, -4), + A: (0, 1, -1, -1, 4, 0, -1, -2, -1, -1, -2, -1, -1, -1, -1, -1, -2, -2, -2, -3), + G: (-3, 0, 1, -2, 0, 6, -2, -1, -2, -2, -2, -2, -2, -3, -4, -4, 0, -3, -3, -2), + N: (-3, 1, 0, -2, -2, 0, 6, 1, 0, 0, -1, 0, 0, -2, -3, -3, -3, -3, -2, -4), + D: (-3, 0, 1, -1, -2, -1, 1, 6, 2, 0, -1, -2, -1, -3, -3, -4, -3, -3, -3, -4), + E: (-4, 0, 0, -1, -1, -2, 0, 2, 5, 2, 0, 0, 1, -2, -3, -3, -3, -3, -2, -3), + Q: (-3, 0, 0, -1, -1, -2, 0, 0, 2, 5, 0, 1, 1, 0, -3, -2, -2, -3, -1, -2), + H: (-3, -1, 0, -2, -2, -2, 1, 1, 0, 0, 8, 0, -1, -2, -3, -3, -2, -1, 2, -2), + R: (-3, -1, -1, -2, -1, -2, 0, -2, 0, 1, 0, 5, 2, -1, -3, -2, -3, -3, -2, -3), + K: (-3, 0, 0, -1, -1, -2, 0, -1, 1, 1, -1, 2, 5, -1, -3, -2, -3, -3, -2, -3), + M: (-1, -1, -1, -2, -1, -3, -2, -3, -2, 0, -2, -1, -1, 5, 1, 2, -2, 0, -1, -1), + I: (-1, -2, -2, -3, -1, -4, -3, -3, -3, -3, -3, -3, -3, 1, 4, 2, 1, 0, -1, -3), + L: (-1, -2, -2, -3, -1, -4, -3, -4, -3, -2, -3, -2, -2, 2, 2, 4, 3, 0, -1, -2), + V: (-1, -2, -2, -2, 0, -3, -3, -3, -2, -2, -3, -3, -2, 1, 3, 1, 4, -1, -1, -3), + F: (-2, -2, -2, -4, -2, -3, -3, -3, -3, -3, -1, -3, -3, 0, 0, 0, -1, 6, 3, 1), + Y: (-2, -2, -2, -3, -2, -3, -2, -3, -2, -1, 2, -2, -2, -1, -1, -1, -1, 3, 7, 2), + W: (-2, -3, -3, -4, -3, -2, -4, -4, -3, -2, -2, -3, -3, -1, -3, -2, -3, 1, 2, 11), +) + +#let _matrix-score(rows, a, b) = { + let row = rows.at(a, default: none) + let index = _weight-index(b) + if row == none or index == none { + none + } else { + row.at(index) + } +} + +#let _residue-weight(candidate, residue, seq-type, config) = { + let pair = _upper(candidate) + ":" + _upper(residue) + let custom = config.at("custom-weights") + if custom.keys().contains(pair) { + return custom.at(pair) + } + if str(config.at("weight-table")) == "structural" { + let score = _matrix-score(_structural-rows, _upper(candidate), _upper(residue)) + if score != none { + return score + } + } + if str(config.at("weight-table")) == "BLOSUM62" { + let score = _matrix-score(_blosum62-rows, _upper(candidate), _upper(residue)) + if score != none { + return score + } + } + if str(config.at("weight-table")) == "PAM250" { + let score = _matrix-score(_pam250-rows, _upper(candidate), _upper(residue)) + if score != none { + return score + } + } + if str(config.at("weight-table")) == "PAM100" { + let score = _matrix-score(_pam100-rows, _upper(candidate), _upper(residue)) + if score != none { + return score + } + } + if candidate == residue { + return 10 + } + let table = str(config.at("weight-table")) + if table == "identity" { + return 0 + } + if _is-similar(candidate, residue, seq-type, config) { + return if table == "structural" { 6 } else { 4 } + } + if _residue-group(candidate, seq-type, config) == _residue-group(residue, seq-type, config) { + return if table == "structural" { 3 } else { 1 } + } + if table == "PAM250" or table == "PAM100" or table == "BLOSUM62" { + return -2 + } + 0 +} + +#let _weighted-consensus(counts, residues, seq-type, config) = { + if counts.keys().len() == 0 { + return (consensus: none, score: 0) + } + let best = counts.keys().first() + let best-score = none + let best-count = 0 + for candidate in counts.keys() { + let score = 0 + for residue in residues { + let key = _upper(residue) + if key == "." or key == "-" or key == "" { + score += config.at("gap-penalty") + } else { + score += _residue-weight(candidate, key, seq-type, config) + } + } + if best-score == none or score > best-score or (score == best-score and counts.at(candidate) > best-count) { + best = candidate + best-score = score + best-count = counts.at(candidate) + } + } + let max-self = calc.max(1, _residue-weight(best, best, seq-type, config)) + let normalized = calc.max(0, calc.min(100, best-score / (max-self * residues.len()) * 100)) + (consensus: best, score: normalized) +} + +#let _matches-sequence(alignment, refs, index) = { + let seq = alignment.at("sequences").at(index) + for ref in refs { + if ref == index + 1 or str(ref) == str(index + 1) or str(ref) == seq.at("name") { + return true + } + } + false +} + +#let _validate-sequence-ref-list(alignment, refs) = { + for ref in refs { + let _ = _resolve-sequence(alignment, ref) + } + none +} + +#let _validate-sequence-ref-map(alignment, refs) = { + for ref in refs.keys() { + let _ = _resolve-sequence(alignment, ref) + } + none +} + +#let _validate-config-sequence-refs(alignment, config) = { + _validate-sequence-ref-list(alignment, config.at("hidden-names")) + _validate-sequence-ref-list(alignment, config.at("hidden-numbers")) + _validate-sequence-ref-list(alignment, config.at("hidden")) + _validate-sequence-ref-list(alignment, config.at("killed")) + _validate-sequence-ref-list(alignment, config.at("no-shade")) + _validate-sequence-ref-list(alignment, config.at("separation-lines")) + _validate-sequence-ref-list(alignment, config.at("subfamily")) + _validate-sequence-ref-map(alignment, config.at("sequence-names")) + _validate-sequence-ref-map(alignment, config.at("sequence-name-colors")) + _validate-sequence-ref-map(alignment, config.at("sequence-number-colors")) + _validate-sequence-ref-map(alignment, config.at("start-numbers")) + _validate-sequence-ref-map(alignment, config.at("sequence-lengths")) + none +} + +#let _sequence-label(alignment, config, sequence, sequence-index) = { + let by-index = config.at("sequence-names").at(str(sequence-index + 1), default: none) + if by-index != none { + return by-index + } + config.at("sequence-names").at(sequence.at("name"), default: sequence.at("name")) +} + +#let _sequence-color(config, sequence, sequence-index, key, default-color) = { + let colors = config.at(key) + let by-index = colors.at(str(sequence-index + 1), default: none) + if by-index != none { + return by-index + } + colors.at(sequence.at("name"), default: default-color) +} + +#let _config-ref-value(map, sequence, sequence-index, default: none) = { + let by-index = map.at(str(sequence-index + 1), default: none) + if by-index != none { + return by-index + } + map.at(sequence.at("name"), default: default) +} + +#let _renumber-position(raw-pos, start, allow-zero) = { + if raw-pos == none { + return none + } + let shifted = start + raw-pos - 1 + if not allow-zero and start < 1 and shifted >= 0 { + shifted + 1 + } else { + shifted + } +} + +#let _rebuild-sequence(sequence, aligned) = { + let positions = () + let raw = "" + let pos = 0 + for ch in _chars(aligned) { + if ch == "." or ch == "-" { + positions.push(none) + } else { + pos += 1 + raw += ch + positions.push(pos) + } + } + sequence.insert("aligned", aligned) + sequence.insert("raw", raw) + sequence.insert("positions", positions) + sequence.insert("length", pos) +} + +#let _apply-single-sequence-options(alignment, config) = { + if alignment.at("sequences").len() != 1 or config.at("single-seq-shift") == none { + return + } + let sequence = alignment.at("sequences").first() + let aligned = sequence.at("aligned") + if not config.at("keep-single-seq-gaps") { + while aligned.starts-with(".") or aligned.starts-with("-") { + aligned = aligned.slice(1) + if aligned.len() == 0 { + break + } + } + } + let shift = int(config.at("single-seq-shift")) + if shift > 0 { + aligned = "." * shift + aligned + } else if shift < 0 { + let remove = calc.min(-shift, aligned.len()) + aligned = aligned.slice(remove) + } + _rebuild-sequence(sequence, aligned) + alignment.insert("columns", aligned.len()) +} + +#let _apply-numbering-overrides(alignment, config) = { + for (idx, sequence) in alignment.at("sequences").enumerate() { + let start = _config-ref-value(config.at("start-numbers"), sequence, idx, default: 1) + if start != 1 { + let positions = () + for pos in sequence.at("positions") { + positions.push(_renumber-position(pos, start, config.at("allow-zero"))) + } + sequence.insert("positions", positions) + } + let length = _config-ref-value(config.at("sequence-lengths"), sequence, idx, default: none) + if length != none { + sequence.insert("length", length) + } + } +} + +#let _functional-mode(config) = { + let option = config.at("shading").at("option", default: none) + if option == none { config.at("functional-default") } else { option } +} + +#let _functional-style(config, residue) = { + let overrides = config.at("functional-style-overrides") + if overrides.keys().contains(residue) { + return overrides.at(residue) + } + let mode = _functional-mode(config) + let groups = config.at("functional-groups") + if not groups.keys().contains(mode) { + return none + } + for group in groups.at(mode) { + if group.at("residues").contains(residue) { + return group + } + } + none +} + +#let _tint-color(effect) = { + if effect == "weak" { + "Gray10" + } else if effect == "strong" { + "Gray30" + } else { + "LightGray" + } +} + +#let _column-tcoffee-score(alignment, config, col) = { + let total = 0 + let count = 0 + for seq in alignment.at("sequences") { + let scores = config.at("tcoffee").at("scores").at(seq.at("name"), default: ()) + if col < scores.len() and scores.at(col) != none { + total += scores.at(col) + count += 1 + } + } + if count == 0 { 0 } else { total / count } +} + +#let _style-for-column(alignment, config, col) = { + let mode = config.at("shading").at("mode") + let seq-type = alignment.at("seq-type") + let residues = () + let counts = (:) + for seq in alignment.at("sequences") { + let char = seq.at("aligned").slice(col, col + 1) + residues.push(char) + if char != "." and char != "-" { + let key = _upper(char) + counts.insert(key, counts.at(key, default: 0) + 1) + } + } + let styles = () + let consensus = none + let consensus-score = 0 + let consensus-forced = false + if counts.keys().len() > 0 { + let max-key = counts.keys().first() + let max-count = counts.at(max-key) + for key in counts.keys() { + if counts.at(key) > max-count { + max-key = key + max-count = counts.at(key) + } + } + consensus = max-key + consensus-score = max-count / alignment.at("sequences").len() * 100 + } + let consensus-source = config.at("consensus").at("source", default: "all") + if consensus-source == "all" and (config.at("weight-table") != "identity" or config.at("custom-weights").keys().len() > 0 or config.at("gap-penalty") != 0) { + let weighted = _weighted-consensus(counts, residues, seq-type, config) + consensus = weighted.at("consensus") + consensus-score = weighted.at("score") + } + if consensus-source != "all" { + let source-index = _resolve-sequence(alignment, consensus-source) + let source-char = _upper(alignment.at("sequences").at(source-index).at("aligned").slice(col, col + 1)) + if source-char == "." or source-char == "-" or source-char == "" { + consensus = none + consensus-score = 0 + } else { + consensus = source-char + consensus-score = counts.at(source-char, default: 0) / alignment.at("sequences").len() * 100 + consensus-forced = true + } + } + let group-majority = none + let group-counts = (:) + for key in counts.keys() { + let group = _residue-group(key, seq-type, config) + if group != none { + let group-key = str(group) + group-counts.insert(group-key, group-counts.at(group-key, default: 0) + counts.at(key)) + } + } + let max-group-count = 0 + for key in group-counts.keys() { + if group-counts.at(key) > max-group-count { + max-group-count = group-counts.at(key) + group-majority = int(key) + } + } + let reference-index = if config.at("shading").at("reference") != none { _resolve-sequence(alignment, config.at("shading").at("reference")) } else { 0 } + let reference-char = alignment.at("sequences").at(reference-index).at("aligned").slice(col, col + 1) + let styled = (kind, char) => { + let style = config.at("residue-style").at(kind) + let token = style.at("case", default: "upper") + let source-char = if char == "*" { config.at("stop-char") } else { char } + let out-char = if token == "upper" { + _upper(source-char) + } else if token == "lower" { + _lower(source-char) + } else if token == "" or token == "normal" { + source-char + } else { + token + } + ( + kind: kind, + char: out-char, + fg: style.at("fg"), + bg: style.at("bg"), + emph: style.at("style", default: "normal") == "italic" or style.at("style", default: "normal") == "oblique", + ) + } + for (res-index, char) in residues.enumerate() { + if char == "." or char == "-" { + styles.push((kind: "gap", char: config.at("gaps").at("char"), fg: config.at("gaps").at("fg"), bg: config.at("gaps").at("bg"), rule: config.at("gaps").at("char") == "rule")) + } else if mode == "T-Coffee" { + let seq-name = alignment.at("sequences").at(res-index).at("name") + let seq-scores = config.at("tcoffee").at("scores").at(seq-name, default: ()) + let score = if col < seq-scores.len() and seq-scores.at(col) != none { seq-scores.at(col) } else { 0 } + styles.push((kind: "tcoffee", char: char, fg: "Black", bg: scale-color("TCoffee", score), score: score)) + } else if mode == "functional" { + let group = _functional-style(config, _upper(char)) + if group == none { + styles.push(styled("nomatch", char)) + } else { + let styled-char = styled("nomatch", char).at("char") + let token = group.at("case", default: "upper") + let out-char = if token == "upper" { + _upper(char) + } else if token == "lower" { + _lower(char) + } else if token == "" or token == "normal" { + char + } else { + token + } + styles.push(( + kind: "functional", + char: if group.keys().contains("case") { out-char } else { styled-char }, + fg: group.at("fg"), + bg: group.at("bg"), + emph: group.at("style", default: "normal") == "italic" or group.at("style", default: "normal") == "oblique", + )) + } + } else if mode == "diverse" { + if char == reference-char { + styles.push((kind: "allmatch", char: ".", fg: "Black", bg: "White")) + } else if _is-similar(_upper(char), _upper(reference-char), seq-type, config) { + styles.push((kind: "conserved", char: ".", fg: "Black", bg: "White")) + } else { + styles.push((kind: "nomatch", char: _lower(char), fg: "Black", bg: "White")) + } + } else if mode == "similar" { + if consensus != none and consensus-score >= config.at("allmatch-threshold") { + styles.push(styled("allmatch", char)) + } else if consensus != none and consensus-score >= config.at("threshold") and char == consensus { + styles.push(styled("conserved", char)) + } else if group-majority != none and max-group-count / alignment.at("sequences").len() * 100 >= config.at("threshold") and _residue-group(_upper(char), seq-type, config) == group-majority { + styles.push(styled("similar", char)) + } else { + styles.push(styled("nomatch", char)) + } + } else if mode == "singleseq" { + styles.push(styled("nomatch", char)) + } else { + if consensus != none and consensus-score >= config.at("allmatch-threshold") { + styles.push(styled("allmatch", char)) + } else if consensus != none and consensus-score >= config.at("threshold") and char == consensus { + styles.push(styled("conserved", char)) + } else { + styles.push(styled("nomatch", char)) + } + } + } + (styles: styles, consensus: consensus, consensus-score: consensus-score, consensus-forced: consensus-forced) +} + +#let _base-cell(char, fg: "Black", bg: "White", lower: false, emph: false, frame: none) = ( + char: if lower { _lower(char) } else { char }, + fg: fg, + bg: bg, + emph: emph, + frame: frame, +) + +#let _merge-cell-delta(cell, delta) = { + if delta == none { + return cell + } + assert(type(delta) == dictionary, message: "typshade: cell-style callbacks must return none or a dictionary") + let updated = cell + for key in ("char", "fg", "bg", "emph", "frame", "frame-thickness", "rule") { + if delta.keys().contains(key) { + updated.insert(key, delta.at(key)) + } + } + if delta.at("case", default: none) == "upper" { + updated.insert("char", _upper(updated.at("char"))) + } else if delta.at("case", default: none) == "lower" { + updated.insert("char", _lower(updated.at("char"))) + } + if delta.at("lower", default: false) { + updated.insert("char", _lower(updated.at("char"))) + } + updated +} + +#let _apply-cell-styles(alignment, config, sequence, sequence-index, column, column-info, style-info, cell) = { + let updated = cell + if config.at("cell-styles").len() == 0 { + return updated + } + let cell-context = ( + alignment: alignment, + sequence: sequence, + sequence-index: sequence-index, + sequence-number: sequence-index + 1, + sequence-name: sequence.at("name"), + column-index: column, + column: column + 1, + position: sequence.at("positions").at(column), + residue: sequence.at("aligned").slice(column, column + 1), + kind: style-info.at("kind", default: "custom"), + consensus: column-info.at("consensus"), + consensus-score: column-info.at("consensus-score"), + consensus-forced: column-info.at("consensus-forced", default: false), + cell: updated, + ) + for callback in config.at("cell-styles") { + updated = _merge-cell-delta(updated, callback(cell-context)) + cell-context.insert("cell", updated) + } + updated +} + +#let _apply-regions(alignment, config, sequence-index, column, cell) = { + let updated = cell + for region in config.at("shade-regions") { + let target = _resolve-sequence(alignment, region.at("sequence")) + if target == sequence-index or region.at("all") { + let seq = alignment.at("sequences").at(target) + if _selection-columns(seq, region.at("selection"), alignment: alignment).contains(column) { + let explicit-bg = region.at("bg", default: none) + let scheme = region.at("scheme", default: config.at("shading").at("scheme")) + let fill = if explicit-bg != none { explicit-bg } else if scheme == "reds" { "BrickRed" } else if scheme == "greens" { "PineGreen" } else if scheme == "grays" { "DarkGray" } else { "RoyalBlue" } + updated.insert("bg", fill) + updated.insert("fg", if region.at("fg", default: none) != none { region.at("fg") } else if fill == "DarkGray" or fill == "PineGreen" or fill == "RoyalBlue" { "White" } else { updated.at("fg") }) + } + } + } + for region in config.at("tint-regions") { + let target = _resolve-sequence(alignment, region.at("sequence")) + if target == sequence-index { + let seq = alignment.at("sequences").at(target) + if _selection-columns(seq, region.at("selection"), alignment: alignment).contains(column) { + let effect = if region.at("intensity", default: "medium") == "medium" { config.at("tint-default") } else { region.at("intensity") } + updated.insert("bg", _tint-color(effect)) + } + } + } + for region in config.at("lower-regions") { + let target = _resolve-sequence(alignment, region.at("sequence")) + if target == sequence-index { + let seq = alignment.at("sequences").at(target) + if _selection-columns(seq, region.at("selection"), alignment: alignment).contains(column) { + updated.insert("char", _lower(updated.at("char"))) + } + } + } + for region in config.at("emph-regions") { + let target = _resolve-sequence(alignment, region.at("sequence")) + if target == sequence-index { + let seq = alignment.at("sequences").at(target) + if _selection-columns(seq, region.at("selection"), alignment: alignment).contains(column) { + let style = if region.at("style", default: "italic") == "italic" { config.at("emph-default") } else { region.at("style") } + updated.insert("emph", style != "normal") + } + } + } + for region in config.at("frame-regions") { + let target = _resolve-sequence(alignment, region.at("sequence")) + if target == sequence-index { + let seq = alignment.at("sequences").at(target) + if _selection-columns(seq, region.at("selection"), alignment: alignment).contains(column) { + updated.insert("frame", region.at("color")) + } + } + } + updated +} + +#let _visible-sequences(alignment, config) = { + if config.at("hide-seqs") { + return () + } + let out = () + for seq in alignment.at("sequences") { + let idx = _resolve-sequence(alignment, seq.at("name")) + 1 + let hidden = config.at("hidden").contains(idx) or config.at("hidden").contains(seq.at("name")) + let killed = config.at("killed").contains(idx) or config.at("killed").contains(seq.at("name")) + if not hidden and not killed { + out.push(seq) + } + } + if config.at("shading").at("mode") == "singleseq" { + let ref = config.at("shading").at("reference", default: 1) + return (alignment.at("sequences").at(_resolve-sequence(alignment, ref)),) + } + if config.at("order") == none { + return out + } + let ordered = () + for ref in config.at("order") { + let idx = _resolve-sequence(alignment, ref) + ordered.push(alignment.at("sequences").at(idx)) + } + ordered +} + +#let _consensus-row(alignment, config, columns, segment) = { + let cells = () + for col in segment { + let info = _style-for-column(alignment, config, col) + let score = info.at("consensus-score") + let level = if info.at("consensus") == none { + "none" + } else if info.at("consensus-forced", default: false) and score < config.at("threshold") { + "conserved" + } else if score >= config.at("allmatch-threshold") { + "allmatch" + } else if score >= config.at("threshold") { + "conserved" + } else { + "none" + } + let char = if level == "none" { + config.at("consensus").at("symbols").at("none") + } else if level == "allmatch" { + let token = config.at("consensus").at("symbols").at("allmatch") + if token == "upper" { + _upper(info.at("consensus")) + } else if token == "lower" { + _lower(info.at("consensus")) + } else { + token + } + } else if level == "conserved" { + let token = config.at("consensus").at("symbols").at("conserved") + if token == "upper" { + _upper(info.at("consensus")) + } else if token == "lower" { + _lower(info.at("consensus")) + } else { + token + } + } else { + config.at("consensus").at("symbols").at("none") + } + let color-style = config.at("consensus").at("colors").at(level) + let bg = if config.at("consensus").at("scale") == none { + color-style.at("bg") + } else { + let scale-score = if config.at("consensus").at("scale") == "T-Coffee" { _column-tcoffee-score(alignment, config, col) } else { score } + scale-color(config.at("consensus").at("scale"), scale-score) + } + cells.push((char: char, fg: color-style.at("fg"), bg: bg, emph: false, frame: none)) + } + (label: config.at("consensus").at("name"), left: "", right: "", cells: cells, row-kind: "consensus") +} + + +#let _row-for-sequence(alignment, config, sequence, sequence-index, segment) = { + let cells = () + let no-shade = _matches-sequence(alignment, config.at("no-shade"), sequence-index) + for col in segment { + let column-info = _style-for-column(alignment, config, col) + let style-info = column-info.at("styles").at(sequence-index) + if no-shade { + let raw-char = sequence.at("aligned").slice(col, col + 1) + if raw-char == "." or raw-char == "-" { + style-info = (char: config.at("gaps").at("char"), fg: config.at("gaps").at("fg"), bg: config.at("gaps").at("bg"), emph: false, rule: config.at("gaps").at("char") == "rule") + } else { + style-info = (char: if raw-char == "*" { config.at("stop-char") } else { raw-char }, fg: "Black", bg: "White", emph: false) + } + } + let cell = (char: style-info.at("char"), fg: style-info.at("fg"), bg: style-info.at("bg"), emph: style-info.at("emph", default: false), frame: none, rule: style-info.at("rule", default: false)) + cell = _apply-cell-styles(alignment, config, sequence, sequence-index, col, column-info, style-info, cell) + cells.push(_apply-regions(alignment, config, sequence-index, col, cell)) + } + let hide-number = _matches-sequence(alignment, config.at("hidden-numbers"), sequence-index) + let left-num = if config.at("numbering").at("show") and config.at("numbering").at("left") { + let pos = none + for col in segment { + if sequence.at("positions").at(col) != none { + pos = sequence.at("positions").at(col) + break + } + } + if pos == none or hide-number { "" } else { str(pos) } + } else { "" } + let right-num = if config.at("numbering").at("show") and config.at("numbering").at("right") { + let pos = none + let pos-col = none + for col in segment.rev() { + if sequence.at("positions").at(col) != none { + pos = sequence.at("positions").at(col) + pos-col = col + break + } + } + if pos != none and sequence.at("length", default: none) != none { + let last-col = none + for (idx, mapped) in sequence.at("positions").enumerate() { + if mapped != none { + last-col = idx + } + } + if pos-col == last-col { + pos = sequence.at("length") + } + } + if pos == none or hide-number { "" } else { str(pos) } + } else { "" } + let label = if _matches-sequence(alignment, config.at("hidden-names"), sequence-index) { "" } else { _sequence-label(alignment, config, sequence, sequence-index) } + ( + label: label, + label-color: _sequence-color(config, sequence, sequence-index, "sequence-name-colors", config.at("names-color")), + number-color: _sequence-color(config, sequence, sequence-index, "sequence-number-colors", config.at("numbering-color")), + left: left-num, + right: right-num, + cells: cells, + row-kind: "sequence", + ) +} + +#let _separation-row(config, segment) = ( + label: "", + left: "", + right: "", + cells: _array-fill(segment.len(), _empty-cell()), + row-kind: "separation", + height: config.at("separation-space"), +) + +#let _row-label-target(row) = { + let kind = row.at("row-kind") + if kind == "feature-text" { + "feature-text-labels" + } else if kind == "feature" { + "feature-style-labels" + } else if kind == "ruler" { + "ruler-label" + } else { + "names" + } +} + +#let _row-cell-target(row) = { + let kind = row.at("row-kind") + if kind == "feature-text" { + "features" + } else if kind == "feature" { + "featurestyles" + } else if kind == "ruler" { + "ruler" + } else { + "residues" + } +} + +#let _name-width(alignment, config) = { + if not config.at("names").at("show") { + return 0pt + } + let widths = (0pt,) + for seq in alignment.at("sequences") { + let idx = _resolve-sequence(alignment, seq.at("name")) + widths.push(measure(text(.._text-params(config, "names"))[#_text-string(config, "names", _sequence-label(alignment, config, seq, idx))]).width) + } + if config.at("consensus").at("show") and config.at("consensus").at("name") != "" { + widths.push(measure(text(.._text-params(config, "names"))[#_text-string(config, "names", config.at("consensus").at("name"))]).width) + } + if config.at("sequence-logo").at("show") { + widths.push(measure(text(.._text-params(config, "names"))[#_text-string(config, "names", config.at("sequence-logo").at("name"))]).width) + } + if config.at("subfamily-logo").at("show") { + widths.push(measure(text(.._text-params(config, "names"))[#_text-string(config, "names", config.at("subfamily-logo").at("name"))]).width) + widths.push(measure(text(.._text-params(config, "names"))[#_text-string(config, "names", config.at("subfamily-logo").at("negative-name"))]).width) + } + for label in config.at("feature-style-names").values() { + widths.push(measure(text(.._text-params(config, "feature-style-labels"))[#_text-string(config, "feature-style-labels", label)]).width) + } + for label in config.at("feature-text-names").values() { + widths.push(measure(text(.._text-params(config, "feature-text-labels"))[#_text-string(config, "feature-text-labels", label)]).width) + } + for label in config.at("ruler-names").values() { + widths.push(measure(text(.._text-params(config, "ruler-label"))[#_text-string(config, "ruler-label", label)]).width) + } + calc.max(..widths) + 6pt +} + +#let _render-table(rows, config, name-width, num-width, cell-width) = { + let fills = () + let strokes = () + let items = () + let columns = () + if config.at("names").at("show") and config.at("names").at("position") == "left" { + columns.push(name-width) + } + if config.at("numbering").at("show") and config.at("numbering").at("left") { + columns.push(num-width) + } + let residue-cols = rows.first().at("cells").len() + for _ in range(0, residue-cols) { + columns.push(cell-width) + } + if config.at("numbering").at("show") and config.at("numbering").at("right") { + columns.push(num-width) + } + if config.at("names").at("show") and config.at("names").at("position") == "right" { + columns.push(name-width) + } + for row in rows { + let row-fills = () + let row-strokes = () + let label-color = row.at("label-color", default: "Black") + let number-color = row.at("number-color", default: config.at("numbering-color")) + let label-target = _row-label-target(row) + let cell-target = _row-cell-target(row) + let hide-sequence-chars = config.at("hide-residues") and row.at("row-kind") == "sequence" + if config.at("names").at("show") and config.at("names").at("position") == "left" { + row-fills.push(none) + row-strokes.push(none) + items.push(align(if config.at("align-right-labels") { right } else { left }, text(.._text-params(config, label-target, fill: resolve-color(label-color)))[#_text-string(config, label-target, row.at("label"))])) + } + if config.at("numbering").at("show") and config.at("numbering").at("left") { + row-fills.push(none) + row-strokes.push(none) + items.push(align(right, text(.._text-params(config, "numbering", fill: resolve-color(number-color)))[#_text-string(config, "numbering", row.at("left"))])) + } + for cell in row.at("cells") { + row-fills.push(if cell.at("bg") == none { none } else { resolve-color(cell.at("bg")) }) + row-strokes.push(if cell.at("frame") == none { none } else { (paint: resolve-color(cell.at("frame")), thickness: cell.at("frame-thickness", default: 0.5pt)) }) + if cell.at("rule", default: false) { + items.push(box(width: 100%, height: config.at("font-size"), inset: 0pt)[ + #align(horizon, rect(width: 100%, height: config.at("gaps").at("rule-thickness"), fill: resolve-color(cell.at("fg")), stroke: none)) + ]) + } else if row.at("row-kind") == "separation" { + items.push(box(width: 100%, height: row.at("height"), inset: 0pt)[]) + } else if cell.keys().contains("rotated") { + items.push(box(width: 100%, height: config.at("font-size") * 3, inset: 0pt)[ + #align(center + horizon, rotate(-90deg, reflow: false)[ + #text(.._text-params(config, cell-target, fill: resolve-color(cell.at("fg"))))[#_text-string(config, cell-target, cell.at("rotated"))] + ]) + ]) + } else if cell.keys().contains("ruler-label") { + items.push(box(width: 100%, inset: 0pt)[ + #align(center + horizon)[ + #text(.._text-params(config, cell-target, fill: resolve-color(cell.at("fg"))))[#_text-string(config, cell-target, cell.at("ruler-label"))] + ] + ]) + } else { + items.push(text(.._text-params(config, cell-target, fill: resolve-color(cell.at("fg")), style: if cell.at("emph") { "italic" } else { auto }, size: if cell.keys().contains("size") { _font-size(config, cell.at("size")) } else { auto }))[#{ + if hide-sequence-chars or (cell.at("char") == "." and not config.at("show-leading-gaps")) { "" } else { _text-string(config, cell-target, cell.at("char")) } + }]) + } + } + if config.at("numbering").at("show") and config.at("numbering").at("right") { + row-fills.push(none) + row-strokes.push(none) + items.push(align(left, text(.._text-params(config, "numbering", fill: resolve-color(number-color)))[#_text-string(config, "numbering", row.at("right"))])) + } + if config.at("names").at("show") and config.at("names").at("position") == "right" { + row-fills.push(none) + row-strokes.push(none) + items.push(align(if config.at("align-right-labels") { left } else { right }, text(.._text-params(config, label-target, fill: resolve-color(label-color)))[#_text-string(config, label-target, row.at("label"))])) + } + fills.push(row-fills) + strokes.push(row-strokes) + } + let table-width = 0pt + for column in columns { + table-width += column + } + box(width: table-width, inset: 0pt)[ + #table(columns: columns, inset: (x: 2pt, y: 1pt), stroke: (x, y) => strokes.at(y).at(x), fill: (x, y) => fills.at(y).at(x), align: center, column-gutter: 0pt, row-gutter: config.at("line-gap"), ..items) + ] +} + +#let _append-feature-blocks(rendered, alignment, config, segment, slots, name-width, num-width, cell-width) = { + for slot in slots { + let rows = _feature-rows(alignment, config, segment, slot) + if rows.len() > 0 { + rendered.push(_render-table(rows, config, name-width, num-width, cell-width)) + let spacing = config.at("feature-slot-spacing").at(slot) + if spacing != 0pt { + rendered.push(v(spacing, weak: false)) + } + } + } +} + +#let _alignment-edge(config) = { + let value = config.at("alignment") + if value == "left" { + left + } else if value == "right" { + right + } else { + center + } +} + +#let _line-count-is-auto(value) = value == auto or str(value) == "auto" + +#let _label-number-width(config, name-width, num-width) = { + let fixed = 0pt + if config.at("names").at("show") { + fixed += name-width + } + if config.at("numbering").at("show") and config.at("numbering").at("left") { + fixed += num-width + } + if config.at("numbering").at("show") and config.at("numbering").at("right") { + fixed += num-width + } + fixed +} + +#let _resolved-residues-per-line(config, display-columns, available-width, cell-width, name-width, num-width) = { + let requested = config.at("residues-per-line") + if not _line-count-is-auto(requested) { + return calc.max(1, int(requested)) + } + let limits = config.at("auto-layout") + let lower = calc.max(1, int(limits.at("min", default: 1))) + let upper = limits.at("max", default: none) + let clamp = value => { + let bounded = calc.max(lower, value) + if upper == none { + bounded + } else { + calc.min(int(upper), bounded) + } + } + if available-width == none or available-width == auto { + return clamp(calc.max(1, calc.min(60, display-columns.len()))) + } + if available-width > 10000pt { + return clamp(calc.max(1, calc.min(60, display-columns.len()))) + } + let fixed = _label-number-width(config, name-width, num-width) + let usable = calc.max(cell-width, available-width - fixed - 6pt) + clamp(calc.max(1, calc.min(display-columns.len(), int(calc.floor(usable / cell-width))))) +} + +#let _resolved-blocks-per-page(alignment, config, available-height) = { + let page = config.at("auto-page") + if not page.at("enabled") { + return none + } + let requested = page.at("blocks") + if requested != auto and requested != none { + return calc.max(1, int(requested)) + } + if requested == none or available-height == none or available-height == auto or available-height > 10000pt { + return none + } + let sequence-rows = _visible-sequences(alignment, config).len() + let consensus-rows = if config.at("consensus").at("show") { 1 } else { 0 } + let ruler-rows = if config.at("ruler").at("show") { 2 } else { 0 } + let logo-rows = (if config.at("sequence-logo").at("show") { 3 } else { 0 }) + (if config.at("subfamily-logo").at("show") and config.at("subfamily").len() > 0 { 3 } else { 0 }) + let feature-count = config.at("features").len() + config.at("structure-data").len() + let feature-rows = calc.min(6, feature-count) + let rows = calc.max(1, sequence-rows + consensus-rows + ruler-rows + logo-rows + feature-rows) + let row-height = config.at("font-size") + config.at("line-gap") + 2pt + let estimated = rows * row-height + config.at("block-gap") + calc.max(1, int(calc.floor(available-height / estimated))) +} + +#let _legend-style-label(kind) = { + if kind == "allmatch" { + "all match" + } else if kind == "conserved" { + "conserved" + } else if kind == "similar" { + "similar" + } else if kind == "gap" { + "gap" + } else if kind == "tcoffee" { + "T-Coffee" + } else { + kind + } +} + +#let _legend-key-part(value) = { + if value == none { + "none" + } else if type(value) == color { + "color" + } else { + str(value) + } +} + +#let _legend-items(alignment, config, columns) = { + if not config.at("legend").at("show") or config.at("shading").at("mode") == "functional" { + return () + } + let items = (:) + let wanted = ("similar", "conserved", "allmatch", "gap", "tcoffee") + for col in columns { + let info = _style-for-column(alignment, config, col) + for style in info.at("styles") { + let kind = style.at("kind", default: "nomatch") + if wanted.contains(kind) { + let key = kind + ":" + _legend-key-part(style.at("fg", default: none)) + ":" + _legend-key-part(style.at("bg", default: none)) + if not items.keys().contains(key) { + items.insert(key, ( + label: _legend-style-label(kind), + fg: style.at("fg", default: "Black"), + bg: style.at("bg", default: "White"), + )) + } + } + } + } + if config.at("cell-styles").len() > 0 and not items.keys().contains("cell-style") { + items.insert("cell-style", (label: "cell-style", fg: "Black", bg: "Gray10")) + } + items.values() +} + +#let _render-block-stack(config, edge, rendered) = { + let aligned = rendered.map(item => align(edge)[#item]) + if config.at("fixed-block-space") { + return stack(spacing: config.at("block-gap"), ..aligned) + } + let body = [] + for (idx, item) in aligned.enumerate() { + if idx > 0 and config.at("block-gap") != 0pt { + body += v(config.at("block-gap"), weak: true) + } + body += item + } + body +} + +#let render-alignment(source, format: auto, commands: (), font: none, font-size: none, residues-per-line: none) = { + context { + let config = _default-config() + if font != none { + config.insert("font", font) + } + if font-size != none { + config.insert("font-size", font-size) + } + if residues-per-line != none { + config.insert("residues-per-line", residues-per-line) + } + for command in commands { + config = _apply-command(config, command) + } + let alignment = read-alignment(source, format: format) + if config.at("seq-type") != none { + alignment.insert("seq-type", config.at("seq-type")) + } + let _ = _validate-config-sequence-refs(alignment, config) + _apply-single-sequence-options(alignment, config) + _apply-numbering-overrides(alignment, config) + let render = (available-width, available-height) => { + let sequences = _visible-sequences(alignment, config) + let display-columns = _display-columns(alignment, config) + let cell-width = (measure(text(.._text-params(config, "residues"))[M]).width + 1.5pt) * config.at("char-stretch") + let name-width = _name-width(alignment, config) + let num-sample = "9" * config.at("numbering-width-digits") + let num-width = measure(text(.._text-params(config, "numbering"))[#num-sample]).width + 4pt + let blocks = () + let step = _resolved-residues-per-line(config, display-columns, available-width, cell-width, name-width, num-width) + let start = 0 + while start < display-columns.len() { + let stop = calc.min(start + step, display-columns.len()) + blocks.push(display-columns.slice(start, stop)) + start = stop + } + let rendered = () + if config.at("captions").at("top") != none { + rendered.push(text(.._text-params(config, "legend"))[#config.at("captions").at("top")]) + } + let legend = _legend-block(config, items: _legend-items(alignment, config, display-columns)) + if legend != none { + rendered.push(legend) + } + let blocks-per-page = _resolved-blocks-per-page(alignment, config, available-height) + for (segment-index, segment) in blocks.enumerate() { + _append-feature-blocks(rendered, alignment, config, segment, _top-feature-slots, name-width, num-width, cell-width) + let rows = () + if config.at("ruler").at("show") and config.at("ruler").at("position") == "top" { + for row in _ruler-rows(alignment, config, segment, "top") { + rows.push(row) + } + if config.at("ruler-spacing").at("top") != 0pt { + rendered.push(_render-table(rows, config, name-width, num-width, cell-width)) + rendered.push(v(config.at("ruler-spacing").at("top"), weak: false)) + rows = () + } + } + if config.at("sequence-logo").at("show") and config.at("sequence-logo").at("position") == "top" { + rendered.push(_logo-block(alignment, config, segment, name-width, num-width, cell-width)) + } + if config.at("subfamily-logo").at("show") and config.at("subfamily-logo").at("position") == "top" and config.at("subfamily").len() > 0 { + rendered.push(_logo-block(alignment, config, segment, name-width, num-width, cell-width, subfamily: true)) + } + if config.at("consensus").at("show") and config.at("consensus").at("position") == "top" { + rows.push(_consensus-row(alignment, config, display-columns, segment)) + } + for seq in sequences { + let seq-index = _resolve-sequence(alignment, seq.at("name")) + rows.push(_row-for-sequence(alignment, config, seq, seq-index, segment)) + if _matches-sequence(alignment, config.at("separation-lines"), seq-index) { + rows.push(_separation-row(config, segment)) + } + } + if config.at("consensus").at("show") and config.at("consensus").at("position") == "bottom" { + rows.push(_consensus-row(alignment, config, display-columns, segment)) + } + if config.at("sequence-logo").at("show") and config.at("sequence-logo").at("position") == "bottom" { + rows.push((label: "", left: "", right: "", cells: _array-fill(segment.len(), _empty-cell()), row-kind: "spacer")) + rendered.push(_render-table(rows, config, name-width, num-width, cell-width)) + rendered.push(_logo-block(alignment, config, segment, name-width, num-width, cell-width)) + rows = () + } + if config.at("subfamily-logo").at("show") and config.at("subfamily-logo").at("position") == "bottom" and config.at("subfamily").len() > 0 { + if rows.len() > 0 { + rendered.push(_render-table(rows, config, name-width, num-width, cell-width)) + rows = () + } + rendered.push(_logo-block(alignment, config, segment, name-width, num-width, cell-width, subfamily: true)) + } + if config.at("ruler").at("show") and config.at("ruler").at("position") == "bottom" { + if rows.len() > 0 and config.at("ruler-spacing").at("bottom") != 0pt { + rendered.push(_render-table(rows, config, name-width, num-width, cell-width)) + rendered.push(v(config.at("ruler-spacing").at("bottom"), weak: false)) + rows = () + } + for row in _ruler-rows(alignment, config, segment, "bottom") { + rows.push(row) + } + } + if rows.len() > 0 { + rendered.push(_render-table(rows, config, name-width, num-width, cell-width)) + } + _append-feature-blocks(rendered, alignment, config, segment, _bottom-feature-slots, name-width, num-width, cell-width) + if blocks-per-page != none and segment-index + 1 < blocks.len() and calc.rem(segment-index + 1, blocks-per-page) == 0 { + rendered.push(pagebreak(weak: true)) + if legend != none and config.at("auto-page").at("repeat-legend") { + rendered.push(legend) + } + } + } + if config.at("captions").at("bottom") != none { + rendered.push(text(.._text-params(config, "legend"))[#config.at("captions").at("bottom")]) + } + let edge = _alignment-edge(config) + _render-block-stack(config, edge, rendered) + } + if _line-count-is-auto(config.at("residues-per-line")) or config.at("auto-page").at("blocks") == auto { + layout(size => render(size.width, size.height)) + } else { + render(none, none) + } + } +} diff --git a/packages/preview/typshade/0.1.3/internal/render/features.typ b/packages/preview/typshade/0.1.3/internal/render/features.typ new file mode 100644 index 0000000000..9c329c9b5e --- /dev/null +++ b/packages/preview/typshade/0.1.3/internal/render/features.typ @@ -0,0 +1,388 @@ +// Copyright (C) 2026 Eito Yoneyama +// SPDX-License-Identifier: GPL-2.0 + +#import "graphs.typ": _graph-rows, _graph-style +#import "../engine/layout.typ": _empty-cell, _ordinal-label, _selection-columns, _selection-string +#import "../model/logo.typ": _resolve-sequence +#import "../model/parser.typ": _array-fill, _chars, _lower, _upper + +#let _top-feature-slots = ("ttttop", "tttop", "ttop", "top") +#let _bottom-feature-slots = ("bottom", "bbottom", "bbbottom", "bbbbottom") + +#let _array-position(items, value) = { + for (idx, item) in items.enumerate() { + if item == value { + return idx + } + } + none +} + +#let _feature-label(config, position, text: false) = { + let labels = if text { config.at("feature-text-names") } else { config.at("feature-style-names") } + let colors = if text { config.at("feature-text-name-colors") } else { config.at("feature-style-name-colors") } + ( + text: labels.at(position, default: ""), + color: colors.at(position, default: colors.at("default")), + ) +} + +#let _roman(index, upper: false) = { + let pairs = ((1000, "m"), (900, "cm"), (500, "d"), (400, "cd"), (100, "c"), (90, "xc"), (50, "l"), (40, "xl"), (10, "x"), (9, "ix"), (5, "v"), (4, "iv"), (1, "i")) + let value = index + let out = "" + for pair in pairs { + while value >= pair.at(0) { + out += pair.at(1) + value -= pair.at(0) + } + } + if upper { _upper(out) } else { out } +} + +#let _structure-template(text, number, letter) = { + let lower-letter = _lower(letter) + str(text) + .replace("\\numcount", str(number)) + .replace("\\alphacount", lower-letter) + .replace("\\Alphacount", letter) + .replace("\\romancount", _roman(number)) + .replace("\\Romancount", _roman(number, upper: true)) + .replace("$\\alpha$", "α") + .replace("$\\beta$", "β") + .replace("$\\pi$", "π") + .replace("$\\circ$", "○") + .replace("$\\uparrow$", "↑") + .replace("$\\diamond$", "◇") + .replace("$_{10}$", "10") + .replace("$", "") +} + +#let _structure-items(alignment, config) = { + let items = () + for entry in config.at("structure-data") { + let prefix = entry.at("kind") + let sequence = entry.at("sequence") + let shown = config.at("structure-show").at(prefix, default: ()) + let data = entry.at("data") + if prefix == "HMMTOP" or prefix == "PHDtopo" { + for (idx, range) in data.at("internal", default: ()).enumerate() { + if shown.contains("internal") { + let appearance = config.at("structure-appearance").at(prefix + ":internal") + let letter = _ordinal-label(idx + 1) + items.push((position: appearance.at("position"), sequence: sequence, selection: _selection-string(range), style: _structure-template(appearance.at("style"), idx + 1, letter), text: _structure-template(appearance.at("text"), idx + 1, letter))) + } + } + for (idx, range) in data.at("external", default: ()).enumerate() { + if shown.contains("external") { + let appearance = config.at("structure-appearance").at(prefix + ":external") + let letter = _ordinal-label(idx + 1) + items.push((position: appearance.at("position"), sequence: sequence, selection: _selection-string(range), style: _structure-template(appearance.at("style"), idx + 1, letter), text: _structure-template(appearance.at("text"), idx + 1, letter))) + } + } + for (idx, range) in data.at("spans", default: data.at("tm", default: ())).enumerate() { + if shown.contains("TM") { + let appearance = config.at("structure-appearance").at(prefix + ":TM") + let letter = _ordinal-label(idx + 1) + items.push((position: appearance.at("position"), sequence: sequence, selection: _selection-string(range), style: _structure-template(appearance.at("style"), idx + 1, letter), text: _structure-template(appearance.at("text"), idx + 1, letter))) + } + } + } else if prefix == "PHDsec" { + for (idx, range) in data.at("alpha", default: ()).enumerate() { + if shown.contains("alpha") { + let appearance = config.at("structure-appearance").at("PHDsec:alpha") + let letter = _ordinal-label(idx + 1) + items.push((position: appearance.at("position"), sequence: sequence, selection: _selection-string(range), style: _structure-template(appearance.at("style"), idx + 1, letter), text: _structure-template(appearance.at("text"), idx + 1, letter))) + } + } + for (idx, range) in data.at("beta", default: ()).enumerate() { + if shown.contains("beta") { + let appearance = config.at("structure-appearance").at("PHDsec:beta") + let letter = _ordinal-label(idx + 1) + items.push((position: appearance.at("position"), sequence: sequence, selection: _selection-string(range), style: _structure-template(appearance.at("style"), idx + 1, letter), text: _structure-template(appearance.at("text"), idx + 1, letter))) + } + } + } else if prefix == "STRIDE" or prefix == "DSSP" { + for key in shown { + for (idx, range) in data.at(key, default: ()).enumerate() { + let appearance = config.at("structure-appearance").at(prefix + ":" + key) + let letter = _ordinal-label(idx + 1) + items.push((position: appearance.at("position"), sequence: sequence, selection: _selection-string(range), style: _structure-template(appearance.at("style"), idx + 1, letter), text: _structure-template(appearance.at("text"), idx + 1, letter))) + } + } + } + } + items +} + +#let _base-matches(pattern, base) = { + let map = ( + A: "A", C: "C", G: "G", T: "TU", U: "TU", + R: "AG", Y: "CTU", K: "GTU", M: "AC", S: "CG", W: "ATU", + B: "CGTU", D: "AGTU", H: "ACTU", V: "ACG", N: "ACGTU", + ) + map.at(_upper(pattern), default: _upper(pattern)).contains(_upper(base)) +} + +#let _codon-matches(pattern, codon) = { + if pattern.len() != 3 or codon.len() != 3 { + return false + } + for idx in range(0, 3) { + if not _base-matches(pattern.slice(idx, idx + 1), codon.slice(idx, idx + 1)) { + return false + } + } + true +} + +#let _translate-codon(config, codon) = { + let cleaned = _upper(str(codon)).replace("U", "T") + for residue in config.at("genetic-code").keys() { + if _codon-matches(config.at("genetic-code").at(residue).replace("U", "T"), cleaned) { + return residue + } + } + "X" +} + +#let _complement-base(base) = { + let pairs = (A: "T", T: "A", U: "A", G: "C", C: "G", R: "Y", Y: "R", K: "M", M: "K", S: "S", W: "W", B: "V", V: "B", D: "H", H: "D", N: "N") + pairs.at(_upper(base), default: _upper(base)) +} + +#let _style-colors(style, default-fg: "Black", default-bg: none) = { + let hit = str(style).matches(regex("\\[([^\\]]+)\\]")) + if hit.len() == 0 { + return (fg: default-fg, bg: default-bg) + } + let parts = hit.first().captures.at(0).split(",").map(part => part.trim()) + (fg: if parts.len() > 0 and parts.first() != "" { parts.first() } else { default-fg }, bg: if parts.len() > 1 and parts.at(1) != "" { parts.at(1) } else { default-bg }) +} + +#let _backtranslation-label(config, triplet, index) = { + let style = config.at("backtranslation").at("label-style") + if style == "vertical" { + triplet.slice(0, 1) + "\n" + triplet.slice(1, 2) + "\n" + triplet.slice(2, 3) + } else if style == "oblique" { + triplet.slice(0, 1) + "/" + triplet.slice(1, 2) + "/" + triplet.slice(2, 3) + } else if style == "zigzag" { + if calc.rem(index, 2) == 0 { triplet } else { triplet.slice(2, 3) + triplet.slice(1, 2) + triplet.slice(0, 1) } + } else { + triplet + } +} + +#let _translation-cells(alignment, config, sequence, style, segment, selected) = { + let cells = _array-fill(segment.len(), _empty-cell()) + let colors = _style-colors(style) + if alignment.at("seq-type") == "P" { + for (idx, col) in segment.enumerate() { + if selected.contains(col) { + let residue = _upper(sequence.at("aligned").slice(col, col + 1)) + if residue != "." and residue != "-" { + cells.at(idx).insert("char", _backtranslation-label(config, config.at("genetic-code").at(residue, default: "NNN"), idx)) + cells.at(idx).insert("fg", colors.at("fg")) + cells.at(idx).insert("bg", colors.at("bg")) + cells.at(idx).insert("size", config.at("backtranslation").at("label-size")) + } + } + } + return cells + } + let codon = "" + let codon-cols = () + for col in selected { + let residue = sequence.at("aligned").slice(col, col + 1) + if residue == "." or residue == "-" { + continue + } + codon += residue + codon-cols.push(col) + if codon.len() == 3 { + let center-col = codon-cols.at(1) + let target = _array-position(segment, center-col) + if target != none { + cells.at(target).insert("char", _translate-codon(config, codon)) + cells.at(target).insert("fg", colors.at("fg")) + cells.at(target).insert("bg", colors.at("bg")) + cells.at(target).insert("size", config.at("backtranslation").at("text-size")) + } + codon = "" + codon-cols = () + } + } + cells +} + +#let _complement-cells(config, sequence, style, segment, selected) = { + let cells = _array-fill(segment.len(), _empty-cell()) + let colors = _style-colors(style) + let lower = str(style).contains("[lower]") + for (idx, col) in segment.enumerate() { + if selected.contains(col) { + let residue = sequence.at("aligned").slice(col, col + 1) + if residue != "." and residue != "-" { + let base = _complement-base(residue) + cells.at(idx).insert("char", if lower { _lower(base) } else { base }) + cells.at(idx).insert("fg", colors.at("fg")) + cells.at(idx).insert("bg", colors.at("bg")) + } + } + } + cells +} + +#let _feature-cell(config, style, col, selected) = { + if not selected.contains(col) { + return _empty-cell() + } + if style == "" { + return (char: "•", fg: "Black", bg: "LightGray", emph: false, frame: none) + } + if style.starts-with("box") { + let fill = "LightGray" + let hit = style.matches(regex("^box\\[([^\\]]+)\\]")) + if hit.len() > 0 { + fill = hit.first().captures.at(0) + } + return (char: "", fg: "Black", bg: fill, emph: false, frame: "Black", frame-thickness: config.at("feature-rule")) + } + if style == "helix" { + return (char: "≋", fg: "Black", bg: none, emph: false, frame: none) + } + if style.starts-with("fill:") { + let symbol = style.split(":").last() + return (char: if symbol.len() > 0 { symbol.slice(0, 1) } else { "•" }, fg: "Black", bg: none, emph: false, frame: none) + } + if style.starts-with("brace") { + return (char: "⌒", fg: "Black", bg: none, emph: false, frame: none) + } + if style.contains("=") { + return (char: "━", fg: "Black", bg: none, emph: false, frame: none) + } + if style.contains("-") or style.contains(">") or style.contains("<") or style.contains(",") { + return (char: "─", fg: "Black", bg: none, emph: false, frame: none) + } + (char: style.slice(0, 1), fg: "Black", bg: "LightGray", emph: false, frame: none) +} + +#let _ruler-rows(alignment, config, segment, position) = { + let seq = alignment.at("sequences").at(_resolve-sequence(alignment, config.at("ruler").at("sequence"))) + let steps = config.at("ruler").at("steps") + let ruler-color = config.at("ruler-colors").at(position, default: config.at("ruler").at("color")) + let ruler-name = config.at("ruler-names").at(position, default: "") + let ruler-name-color = config.at("ruler-name-colors").at(position, default: ruler-color) + let alt-labels = config.at("ruler-labels").at(position, default: (:)) + let rotated = config.at("ruler-rotation").at(position, default: false) + let ticks = () + let labels = _array-fill(segment.len(), _empty-cell()) + for col in segment { + let pos = seq.at("positions").at(col) + if pos != none and calc.rem(pos, steps) == 0 { + ticks.push((char: "|", fg: ruler-color, bg: none, emph: false, frame: none)) + } else { + ticks.push(_empty-cell()) + } + } + for (idx, col) in segment.enumerate() { + let pos = seq.at("positions").at(col) + if pos != none and calc.rem(pos, steps) == 0 { + let override = alt-labels.at(str(pos), default: none) + let text = if override == none { str(pos) } else { override.at("text") } + let color = if override == none or override.at("color") == none { ruler-color } else { override.at("color") } + if rotated { + labels.at(idx).insert("char", "") + labels.at(idx).insert("rotated", text) + labels.at(idx).insert("fg", color) + } else { + labels.at(idx).insert("char", "") + labels.at(idx).insert("ruler-label", text) + labels.at(idx).insert("fg", color) + } + } + } + let label-row = (label: ruler-name, label-color: ruler-name-color, left: "", right: "", cells: labels, row-kind: "ruler") + let tick-row = (label: "", left: "", right: "", cells: ticks, row-kind: "ruler") + if position == "bottom" { + (tick-row, label-row) + } else { + (label-row, tick-row) + } +} + +#let _feature-rows(alignment, config, segment, position) = { + let rows = () + let entries = () + for item in config.at("features") { + entries.push(item) + } + for item in _structure-items(alignment, config) { + entries.push(item) + } + for item in entries { + if item.at("position") != position { + continue + } + let seq = alignment.at("sequences").at(_resolve-sequence(alignment, item.at("sequence"))) + let selected = _selection-columns(seq, item.at("selection"), alignment: alignment) + let graph = _graph-style(item.at("style")) + let cells = if graph != none { + none + } else if str(item.at("style")).starts-with("translate") { + _translation-cells(alignment, config, seq, item.at("style"), segment, selected) + } else if str(item.at("style")).starts-with("complement") { + _complement-cells(config, seq, item.at("style"), segment, selected) + } else { + let out = () + for col in segment { + out.push(_feature-cell(config, item.at("style"), col, selected)) + } + out + } + if graph != none { + let style-label = _feature-label(config, position) + for (row-index, graph-row) in _graph-rows(alignment, config, seq, selected, segment, item.at("style"), position: position).enumerate() { + rows.push(( + label: if row-index == 0 { style-label.at("text") } else { "" }, + label-color: style-label.at("color"), + left: "", + right: "", + cells: graph-row, + row-kind: "feature", + )) + } + } else { + let style-label = _feature-label(config, position) + rows.push((label: style-label.at("text"), label-color: style-label.at("color"), left: "", right: "", cells: cells, row-kind: "feature")) + } + let style-text = if type(item.at("style")) == str { item.at("style") } else { "" } + let inline-text = if style-text.starts-with("box") and style-text.contains(":") { + style-text.split(":").last() + } else { + "" + } + let label = if item.at("text") != "" { item.at("text") } else { inline-text } + if label != "" { + let text-label = _feature-label(config, position, text: true) + let label-cells = _array-fill(segment.len(), _empty-cell()) + let in-segment = () + for (idx, col) in segment.enumerate() { + if selected.contains(col) { + in-segment.push(idx) + } + } + if in-segment.len() > 0 { + let start = calc.max(0, calc.min(in-segment.first(), in-segment.last()) - 1) + for (offset, ch) in _chars(label).enumerate() { + let target = start + offset + if target < label-cells.len() { + label-cells.at(target).insert("char", ch) + } + } + } + rows.push((label: text-label.at("text"), label-color: text-label.at("color"), left: "", right: "", cells: label-cells, row-kind: "feature-text")) + } + } + rows +} diff --git a/packages/preview/typshade/0.1.3/internal/render/graphs.typ b/packages/preview/typshade/0.1.3/internal/render/graphs.typ new file mode 100644 index 0000000000..cdd9388e31 --- /dev/null +++ b/packages/preview/typshade/0.1.3/internal/render/graphs.typ @@ -0,0 +1,626 @@ +// Copyright (C) 2026 Eito Yoneyama +// SPDX-License-Identifier: GPL-2.0 + +#import "../engine/layout.typ": _empty-cell +#import "../model/palette.typ": resolve-color, scale-color +#import "../model/parser.typ": _source-is-path, _source-text, _split-lines, _upper + +#let _hydropathy-scale = ( + A: 1.8, C: 2.5, D: -3.5, E: -3.5, F: 2.8, G: -0.4, H: -3.2, I: 4.5, + K: -3.9, L: 3.8, M: 1.9, N: -3.5, P: -1.6, Q: -3.5, R: -4.5, S: -0.8, + T: -0.7, V: 4.2, W: -0.9, Y: -1.3, +) + +#let _molweight-scale = ( + A: 89.1, C: 121.2, D: 133.1, E: 147.1, F: 165.2, G: 75.1, H: 155.2, I: 131.2, + K: 146.2, L: 131.2, M: 149.2, N: 132.1, P: 115.1, Q: 146.1, R: 174.2, S: 105.1, + T: 119.1, V: 117.1, W: 204.2, Y: 181.2, +) + +#let _charge-scale = ( + D: -1.0, E: -1.0, K: 1.0, R: 1.0, H: 0.5, +) + +#let _graph-scales = ("BlackWhite", "WhiteBlack", "BlueRed", "RedBlue", "GreenRed", "RedGreen", "ColdHot", "HotCold", "TCoffee") +#let _builtin-graph-metrics = ("hydrophobicity", "molweight", "charge", "conservation", "entropy", "gap-fraction", "gaps", "coverage", "identity", "identity-to-reference") + +#let _array-position(items, value) = { + for (idx, item) in items.enumerate() { + if item == value { + return idx + } + } + none +} + +#let _graph-is-stacked(parsed) = parsed.at("kind") == "stackedbars" or parsed.at("kind") == "frustratometer" + +#let _parse-number(value) = { + let text = str(value).trim() + if text == "" or text == "NaN" or text == "nan" { + none + } else { + float(text) + } +} + +#let _graph-style(style) = { + if type(style) == dictionary { + if not style.keys().contains("kind") or not style.keys().contains("metric") { + return none + } + return ( + kind: style.at("kind"), + metric: style.at("metric"), + min: style.at("min", default: none), + max: style.at("max", default: none), + options: style.at("options", default: ()), + ) + } + let text = str(style).trim() + let hit = text.matches(regex("^(bar|color|stackedbars|frustratometer)(?:\\[([^\\]]*)\\])?:(.+?)(?:\\[([^\\]]*)\\])?$")) + if hit.len() == 0 { + return none + } + let captures = hit.first().captures + let kind = captures.at(0) + let range-text = captures.at(1, default: "") + let metric = captures.at(2).trim() + let option-text = captures.at(3, default: "") + let min = none + let max = none + if range-text != "" { + let parts = range-text.split(",") + if parts.len() >= 2 { + min = _parse-number(parts.at(0)) + max = _parse-number(parts.at(1)) + } + } + let options = if option-text == "" { () } else { option-text.split(",").map(part => part.trim()) } + (kind: kind, metric: metric, min: min, max: max, options: options) +} + +#let _graph-range(metric) = if metric == "hydrophobicity" { + (-4.5, 4.5) +} else if metric == "molweight" { + (75.1, 204.2) +} else if metric == "charge" { + (-1.0, 1.0) +} else { + (0.0, 100.0) +} + +#let _graph-range-from-style(parsed, series: none) = { + if parsed.at("min") != none and parsed.at("max") != none { + return (parsed.at("min"), parsed.at("max")) + } + if parsed.at("kind") == "frustratometer" { + return (0.0, 1.0) + } + if _builtin-graph-metrics.contains(parsed.at("metric")) { + return _graph-range(parsed.at("metric")) + } + let min = none + let max = none + for item in series { + let values = if type(item) == array or type(item) == content { item } else { (item,) } + for value in values { + if value == none { + continue + } + if min == none or value < min { + min = value + } + if max == none or value > max { + max = value + } + } + } + if min == none or max == none { + (0.0, 1.0) + } else if min == max { + (min, max + 1.0) + } else { + (min, max) + } +} + +#let _graph-column-counts(alignment, col) = { + let counts = (:) + let total = 0 + let gaps = 0 + for seq in alignment.at("sequences") { + let residue = _upper(seq.at("aligned").slice(col, col + 1)) + if residue == "." or residue == "-" or residue == "" { + gaps += 1 + continue + } + counts.insert(residue, counts.at(residue, default: 0) + 1) + total += 1 + } + (counts: counts, total: total, gaps: gaps) +} + +#let _graph-conservation(alignment, col) = { + let data = _graph-column-counts(alignment, col) + let counts = data.at("counts") + let total = data.at("total") + if total == 0 { + return 0.0 + } + let top = 0 + for key in counts.keys() { + if counts.at(key) > top { + top = counts.at(key) + } + } + top / total * 100.0 +} + +#let _graph-entropy(alignment, col) = { + let data = _graph-column-counts(alignment, col) + let counts = data.at("counts") + let total = data.at("total") + if total == 0 { + return 0.0 + } + let entropy = 0.0 + for key in counts.keys() { + let p = counts.at(key) / total + if p > 0 { + entropy += -p * calc.log(p) / calc.log(2) + } + } + let max-entropy = if alignment.at("seq-type") == "N" { 2.0 } else { calc.log(20.0) / calc.log(2) } + calc.max(0.0, calc.min(100.0, entropy / max-entropy * 100.0)) +} + +#let _graph-gap-fraction(alignment, col) = _graph-column-counts(alignment, col).at("gaps") / alignment.at("sequences").len() * 100.0 + +#let _graph-coverage(alignment, col) = _graph-column-counts(alignment, col).at("total") / alignment.at("sequences").len() * 100.0 + +#let _graph-identity(alignment, sequence, col) = { + let residue = _upper(sequence.at("aligned").slice(col, col + 1)) + if residue == "." or residue == "-" or residue == "" { + return none + } + let total = 0 + let hits = 0 + for seq in alignment.at("sequences") { + let other = _upper(seq.at("aligned").slice(col, col + 1)) + if other == "." or other == "-" or other == "" { + continue + } + total += 1 + if other == residue { + hits += 1 + } + } + if total == 0 { none } else { hits / total * 100.0 } +} + +#let _builtin-graph-value(alignment, sequence, col, metric) = { + let residue = _upper(sequence.at("aligned").slice(col, col + 1)) + if (metric == "hydrophobicity" or metric == "molweight" or metric == "charge") and (residue == "." or residue == "-" or residue == "") { + return none + } + if metric == "hydrophobicity" { + return _hydropathy-scale.at(residue, default: 0.0) + } + if metric == "molweight" { + return _molweight-scale.at(residue, default: 100.0) + } + if metric == "charge" { + return _charge-scale.at(residue, default: 0.0) + } + if metric == "conservation" { + return _graph-conservation(alignment, col) + } + if metric == "entropy" { + return _graph-entropy(alignment, col) + } + if metric == "gap-fraction" or metric == "gaps" { + return _graph-gap-fraction(alignment, col) + } + if metric == "coverage" { + return _graph-coverage(alignment, col) + } + if metric == "identity" or metric == "identity-to-reference" { + return _graph-identity(alignment, sequence, col) + } + none +} + +#let _parse-inline-graph-data(text, stacked: false) = { + let source = str(text).trim() + if stacked { + let rows = () + for hit in source.matches(regex("\\(([^\\)]*)\\)")) { + let values = () + for part in hit.captures.at(0).split(",") { + values.push(_parse-number(part)) + } + rows.push((position: none, values: values)) + } + return rows + } + let values = () + for part in source.split(",") { + values.push(_parse-number(part)) + } + values.map(value => (position: none, values: (value,))) +} + +#let _parse-graph-line(line, stacked: false) = { + let trimmed = str(line).trim() + if trimmed == "" { + return none + } + let first = trimmed.slice(0, 1) + if first.matches(regex("[A-Za-z]")).len() > 0 and not trimmed.starts-with("NaN") and not trimmed.starts-with("nan") { + return none + } + let position = none + let body = trimmed + let numbered = trimmed.matches(regex("^(-?\\d+)\\s*:\\s*(.+)$")) + if numbered.len() > 0 { + position = int(numbered.first().captures.at(0)) + body = numbered.first().captures.at(1) + } + let values = () + for part in body.split(",") { + values.push(_parse-number(part)) + } + if not stacked and values.len() > 1 { + values = (values.first(),) + } + (position: position, values: values) +} + +#let _read-graph-data(source, stacked: false) = { + let rows = () + for line in _split-lines(_source-text(source)) { + let parsed = _parse-graph-line(line, stacked: stacked) + if parsed != none { + rows.push(parsed) + } + } + rows +} + +#let _read-frustr-data(source) = { + let rows = () + for line in _split-lines(_source-text(source)) { + let trimmed = str(line).trim() + if trimmed == "" or trimmed.starts-with("#") { + continue + } + let parts = trimmed.split().filter(part => part != "") + if parts.len() < 9 { + continue + } + let residue = _parse-number(parts.at(0)) + if residue == none { + continue + } + let rel-high = _parse-number(parts.at(6)) + let rel-neutral = _parse-number(parts.at(7)) + let rel-min = _parse-number(parts.at(8)) + rows.push((position: int(residue), values: (rel-min, rel-neutral, rel-high))) + } + rows +} + +#let _graph-data-source(parsed) = { + let metric = parsed.at("metric") + if type(metric) == str and _builtin-graph-metrics.contains(metric) { + return "builtin" + } + if type(metric) == bytes or _source-is-path(metric) { + return if parsed.at("kind") == "frustratometer" { "frustr" } else { "source" } + } + if parsed.at("kind") == "frustratometer" { + return "frustr" + } + if type(metric) == str and metric.contains("\n") { + return "source" + } + if type(metric) == str and parsed.at("kind") == "stackedbars" and metric.contains("(") { + return "inline" + } + if type(metric) == str and parsed.at("kind") != "stackedbars" and metric.contains(",") { + return "inline" + } + "source" +} + +#let _graph-series(parsed, alignment, sequence, selected) = { + let source = _graph-data-source(parsed) + let stacked = _graph-is-stacked(parsed) + if source == "builtin" { + let out = () + for col in selected { + if stacked { + out.push((_builtin-graph-value(alignment, sequence, col, parsed.at("metric")),)) + } else { + out.push(_builtin-graph-value(alignment, sequence, col, parsed.at("metric"))) + } + } + return out + } + let rows = if source == "inline" { + _parse-inline-graph-data(parsed.at("metric"), stacked: stacked) + } else if source == "frustr" { + _read-frustr-data(parsed.at("metric")) + } else { + _read-graph-data(parsed.at("metric"), stacked: stacked) + } + let numbered = rows.any(row => row.at("position") != none) + let out = () + if numbered { + let lookup = (:) + for row in rows { + if row.at("position") != none { + lookup.insert(str(row.at("position")), row.at("values")) + } + } + for col in selected { + let pos = sequence.at("positions").at(col) + let values = if pos == none or not lookup.keys().contains(str(pos)) { () } else { lookup.at(str(pos)) } + if stacked { + out.push(values) + } else { + out.push(if values.len() > 0 { values.first() } else { none }) + } + } + } else { + for idx in range(0, selected.len()) { + if idx < rows.len() { + let values = rows.at(idx).at("values") + out.push(if stacked { values } else { if values.len() > 0 { values.first() } else { none } }) + } else { + out.push(if stacked { () } else { none }) + } + } + } + out +} + +#let _graph-normalized(bounds, value) = { + if value == none { + return none + } + let lo = bounds.at(0) + let hi = bounds.at(1) + if hi == lo { + return 0.0 + } + calc.max(0.0, calc.min(1.0, (value - lo) / (hi - lo))) +} + +#let _graph-stretch(config, kind, position) = { + let table = if kind == "color" { config.at("color-scale-stretch") } else { config.at("bar-graph-stretch") } + table.at(position, default: table.at("default")) +} + +#let _graph-bar-colors(parsed, value) = { + let options = parsed.at("options") + let fg = if options.len() >= 1 and options.at(0) != "" { + options.at(0) + } else if parsed.at("metric") == "charge" and value < 0 { + "BrickRed" + } else if parsed.at("metric") == "charge" and value > 0 { + "RoyalBlue" + } else { + "Gray60" + } + let bg = if options.len() >= 2 and options.at(1) != "" { options.at(1) } else { none } + (fg: fg, bg: bg) +} + +#let _graph-color-scale(parsed) = { + let options = parsed.at("options") + if options.len() >= 1 and options.at(0) != "" { + options.at(0) + } else if parsed.at("metric") == "charge" { + "RedBlue" + } else if parsed.at("metric") == "conservation" { + "ColdHot" + } else if parsed.at("metric") == "entropy" or parsed.at("metric") == "gap-fraction" or parsed.at("metric") == "gaps" { + "WhiteBlack" + } else if parsed.at("metric") == "coverage" or parsed.at("metric") == "identity" or parsed.at("metric") == "identity-to-reference" { + "ColdHot" + } else { + "WhiteBlack" + } +} + +#let _stack-colors(parsed, count) = { + let options = parsed.at("options") + if parsed.at("kind") == "frustratometer" { + if options.len() >= 3 { + return (colors: (resolve-color(options.at(0)), resolve-color(options.at(1)), resolve-color(options.at(2))), background: none) + } + return (colors: (resolve-color("PineGreen"), resolve-color("Gray60"), resolve-color("BrickRed")), background: none) + } + if options.len() == 0 { + let out = () + for idx in range(0, count) { + let level = if count <= 1 { 50 } else { calc.round(idx * 100 / (count - 1)) } + out.push(scale-color("BlueRed", level)) + } + return (colors: out, background: none) + } + if _graph-scales.contains(options.first()) { + let out = () + for idx in range(0, count) { + let level = if count <= 1 { 50 } else { calc.round(idx * 100 / (count - 1)) } + out.push(scale-color(options.first(), level)) + } + let background = if options.len() >= 2 and options.at(1) != "" { options.at(1) } else { none } + return (colors: out, background: background) + } + let out = () + for idx in range(0, count) { + out.push(resolve-color(options.at(calc.min(idx, options.len() - 1)))) + } + (colors: out, background: none) +} + +#let _graph-resolution(parsed, config, position) = if parsed.at("kind") == "color" { + calc.max(1, int(calc.ceil(_graph-stretch(config, "color", position)))) +} else { + calc.max(1, int(calc.ceil(8 * _graph-stretch(config, "bar", position)))) +} + +#let _graph-fill-cell(fill, background: none, frame: none) = ( + char: "", + fg: "Black", + bg: fill, + emph: false, + frame: frame, +) + +#let _graph-color-rows(parsed, config, series, selected, segment, position) = { + let rows = () + let levels = () + let bounds = _graph-range-from-style(parsed, series: series) + for value in series { + levels.push(_graph-normalized(bounds, value)) + } + let repeat = _graph-resolution(parsed, config, position) + for _ in range(0, repeat) { + let cells = () + for col in segment { + let idx = _array-position(selected, col) + if idx == none { + cells.push(_empty-cell()) + } else { + let level = levels.at(idx) + if level == none { + cells.push(_empty-cell()) + } else { + cells.push(_graph-fill-cell(scale-color(_graph-color-scale(parsed), calc.round(level * 100)), frame: if parsed.at("metric") == "conservation" { resolve-color("Gray40") } else { none })) + } + } + } + rows.push(cells) + } + rows +} + +#let _bar-segment(level, lo, hi) = level >= lo and level < hi + +#let _graph-bar-rows(parsed, config, series, selected, segment, position) = { + let rows = () + let bounds = _graph-range-from-style(parsed, series: series) + let baseline = if bounds.at(0) < 0 and bounds.at(1) > 0 { _graph-normalized(bounds, 0.0) } else if bounds.at(1) <= 0 { 1.0 } else { 0.0 } + let repeat = _graph-resolution(parsed, config, position) + let bg = if parsed.at("options").len() >= 2 and parsed.at("options").at(1) != "" { parsed.at("options").at(1) } else { none } + for row in range(0, repeat) { + let level = 1.0 - row / repeat + let cells = () + for col in segment { + let idx = _array-position(selected, col) + if idx == none { + cells.push(_empty-cell()) + } else { + let value = series.at(idx) + let normalized = _graph-normalized(bounds, value) + if normalized == none { + cells.push(_empty-cell()) + } else { + let start = calc.min(normalized, baseline) + let stop = calc.max(normalized, baseline) + if _bar-segment(level, start, stop + 1.0 / repeat) { + let colors = _graph-bar-colors(parsed, value) + cells.push(_graph-fill-cell(resolve-color(colors.at("fg")), background: colors.at("bg"))) + } else if bg != none { + cells.push(_graph-fill-cell(resolve-color(bg))) + } else { + cells.push(_empty-cell()) + } + } + } + } + rows.push(cells) + } + rows +} + +#let _graph-stacked-rows(parsed, config, series, selected, segment, position) = { + let rows = () + let bounds = _graph-range-from-style(parsed, series: series) + let baseline = if bounds.at(0) < 0 and bounds.at(1) > 0 { _graph-normalized(bounds, 0.0) } else if bounds.at(1) <= 0 { 1.0 } else { 0.0 } + let max-count = 0 + for values in series { + if values.len() > max-count { + max-count = values.len() + } + } + let palette = _stack-colors(parsed, max-count) + let repeat = _graph-resolution(parsed, config, position) + for row in range(0, repeat) { + let level = 1.0 - row / repeat + let cells = () + for col in segment { + let idx = _array-position(selected, col) + if idx == none { + cells.push(_empty-cell()) + } else { + let values = series.at(idx) + let segments = () + let pos-cum = 0.0 + let neg-cum = 0.0 + for (value-index, value) in values.enumerate() { + if value == none { + continue + } + if value >= 0 { + let start = _graph-normalized(bounds, pos-cum) + pos-cum += value + let stop = _graph-normalized(bounds, pos-cum) + segments.push((lo: start, hi: stop, color: palette.at("colors").at(calc.min(value-index, palette.at("colors").len() - 1)))) + } else { + let start = _graph-normalized(bounds, neg-cum) + neg-cum += value + let stop = _graph-normalized(bounds, neg-cum) + segments.push((lo: stop, hi: start, color: palette.at("colors").at(calc.min(value-index, palette.at("colors").len() - 1)))) + } + } + let fill = none + for segment-data in segments { + if _bar-segment(level, segment-data.at("lo"), segment-data.at("hi") + 1.0 / repeat) { + fill = segment-data.at("color") + } + } + if fill != none { + cells.push(_graph-fill-cell(fill)) + } else if palette.at("background") != none { + cells.push(_graph-fill-cell(resolve-color(palette.at("background")))) + } else if baseline != none and calc.abs(level - baseline) <= 1.0 / repeat { + cells.push(_graph-fill-cell(resolve-color("Gray30"))) + } else { + cells.push(_empty-cell()) + } + } + } + rows.push(cells) + } + rows +} + +#let _graph-rows(alignment, config, sequence, selected, segment, style, position: none) = { + let parsed = _graph-style(style) + if parsed == none { + return () + } + let series = _graph-series(parsed, alignment, sequence, selected) + if parsed.at("kind") == "color" { + return _graph-color-rows(parsed, config, series, selected, segment, position) + } else if parsed.at("kind") == "stackedbars" or parsed.at("kind") == "frustratometer" { + return _graph-stacked-rows(parsed, config, series, selected, segment, position) + } else { + return _graph-bar-rows(parsed, config, series, selected, segment, position) + } +} diff --git a/packages/preview/typshade/0.1.3/internal/render/logos.typ b/packages/preview/typshade/0.1.3/internal/render/logos.typ new file mode 100644 index 0000000000..f03535504d --- /dev/null +++ b/packages/preview/typshade/0.1.3/internal/render/logos.typ @@ -0,0 +1,160 @@ +// Copyright (C) 2026 Eito Yoneyama +// SPDX-License-Identifier: GPL-2.0 + +#import "../model/logo.typ": _logo-column-items, _logo-max-bits, _logo-residue-color +#import "../model/palette.typ": resolve-color +#import "../model/parser.typ": _lower +#import "../model/text-style.typ": _text-params, _text-string + +#let _logo-height(config) = 28pt * config.at("sequence-logo").at("stretch") + +#let _logo-residue(item, config, seq-type, subfamily) = { + let value = item.at("value") + let size = 5pt + 18pt * (calc.abs(value) / _logo-max-bits(seq-type)) + let residue = if subfamily and value < 0 { _lower(item.at("residue")) } else { item.at("residue") } + text(.._text-params(config, "residues", fill: resolve-color(_logo-residue-color(config, seq-type, item.at("residue"), subfamily: subfamily)), size: size))[#_text-string(config, "residues", residue)] +} + +#let _logo-stack(items, config, seq-type, subfamily, height, edge) = { + box(height: height, inset: 0pt)[#align(edge + center, stack(spacing: -1pt, ..items.map(item => _logo-residue(item, config, seq-type, subfamily))))] +} + +#let _logo-scale-content(config, seq-type, subfamily: false) = { + let max-bits = calc.round(_logo-max-bits(seq-type) * 10) / 10 + let logo-scale-color = resolve-color(config.at("logo-scale").at("color")) + let height = _logo-height(config) + let negative = subfamily and config.at("subfamily-logo").at("show-negatives") + if not negative { + return box(height: height, inset: 0pt)[#align(center + horizon, stack( + spacing: 1pt, + text(.._text-params(config, "ruler", fill: logo-scale-color, size: 6pt))[#str(max-bits)], + rect(width: 0.6pt, height: height - 14pt, fill: logo-scale-color), + text(.._text-params(config, "ruler", fill: logo-scale-color, size: 6pt))[0], + ))] + } + box(height: height + 12pt, inset: 0pt)[#align(center + horizon, stack( + spacing: 1pt, + text(.._text-params(config, "ruler", fill: logo-scale-color, size: 6pt))[#str(max-bits)], + rect(width: 0.6pt, height: height / 2 - 5pt, fill: logo-scale-color), + text(.._text-params(config, "ruler", fill: logo-scale-color, size: 6pt))[0], + rect(width: 0.6pt, height: height / 2 - 5pt, fill: logo-scale-color), + text(.._text-params(config, "ruler", fill: logo-scale-color, size: 6pt))[-#str(max-bits)], + ))] +} + +#let _logo-name-cell(config, subfamily: false) = { + let height = _logo-height(config) + let label-color = resolve-color(config.at("legend").at("color")) + if subfamily and config.at("subfamily-logo").at("show-negatives") { + return box(height: height + 12pt, inset: 0pt)[#align(left + horizon, stack( + spacing: 1pt, + box(height: 6pt, inset: 0pt)[], + box(height: height / 2, inset: 0pt)[#align(left + bottom, text(.._text-params(config, "names", fill: label-color))[#_text-string(config, "names", config.at("subfamily-logo").at("name"))])], + box(height: 0pt, inset: 0pt)[], + box(height: height / 2, inset: 0pt)[#align(left + top, text(.._text-params(config, "names", fill: label-color))[#_text-string(config, "names", config.at("subfamily-logo").at("negative-name"))])], + box(height: 6pt, inset: 0pt)[], + ))] + } + let label = if subfamily { config.at("subfamily-logo").at("name") } else { config.at("sequence-logo").at("name") } + box(height: height, inset: 0pt)[#align(left + horizon, text(.._text-params(config, "names", fill: label-color))[#_text-string(config, "names", label)])] +} + +#let _logo-column(alignment, config, col, subfamily: false) = { + let items = _logo-column-items(alignment, config, col, subfamily: subfamily) + if items.len() == 0 { + return box(height: if subfamily and config.at("subfamily-logo").at("show-negatives") { _logo-height(config) + 12pt } else { _logo-height(config) }, inset: 0pt)[] + } + let seq-type = alignment.at("seq-type") + if not subfamily { + return _logo-stack(items, config, seq-type, false, _logo-height(config), bottom) + } + let positive = items.filter(it => it.at("value") > 0) + let negative = if config.at("subfamily-logo").at("show-negatives") { items.filter(it => it.at("value") < 0) } else { () } + let pos-hit = config.at("relevance").at("show") and positive.any(it => it.at("value") >= config.at("relevance").at("threshold")) + let neg-hit = config.at("relevance").at("show") and negative.any(it => -it.at("value") >= config.at("relevance").at("threshold")) + box(height: _logo-height(config) + 12pt, inset: 0pt)[#align(center + horizon, stack( + spacing: 0pt, + box(height: 6pt, inset: 0pt)[#align(center + horizon, if pos-hit { text(.._text-params(config, "ruler", fill: resolve-color(config.at("relevance").at("color")), size: 6pt))[#_text-string(config, "ruler", config.at("relevance").at("char"))]} else { [] })], + _logo-stack(positive, config, seq-type, true, _logo-height(config) / 2, bottom), + rect(width: 80%, height: 0.35pt, fill: resolve-color(config.at("logo-scale").at("color"))), + _logo-stack(negative, config, seq-type, true, _logo-height(config) / 2, top), + box(height: 6pt, inset: 0pt)[#align(center + horizon, if neg-hit { text(.._text-params(config, "ruler", fill: resolve-color(config.at("relevance").at("color")), size: 6pt))[#_text-string(config, "ruler", config.at("relevance").at("char"))]} else { [] })], + ))] +} + +#let _logo-table(alignment, config, segment, name-width, num-width, cell-width, subfamily: false) = { + let columns = () + let items = () + if config.at("names").at("show") and config.at("names").at("position") == "left" { + columns.push(name-width) + items.push(_logo-name-cell(config, subfamily: subfamily)) + } + if config.at("numbering").at("show") and config.at("numbering").at("left") { + columns.push(num-width) + items.push([]) + } + for col in segment { + columns.push(cell-width) + items.push(_logo-column(alignment, config, col, subfamily: subfamily)) + } + if config.at("numbering").at("show") and config.at("numbering").at("right") { + columns.push(num-width) + items.push([]) + } + if config.at("names").at("show") and config.at("names").at("position") == "right" { + columns.push(name-width) + items.push(_logo-name-cell(config, subfamily: subfamily)) + } + table(columns: columns, inset: 0pt, stroke: none, align: center, column-gutter: 0pt, row-gutter: 0pt, ..items) +} + +#let _logo-block(alignment, config, segment, name-width, num-width, cell-width, subfamily: false) = { + let columns = () + let items = () + let show-left = config.at("logo-scale").at("show") and (config.at("logo-scale").at("position") == "left" or config.at("logo-scale").at("position") == "leftright") + let show-right = config.at("logo-scale").at("show") and (config.at("logo-scale").at("position") == "right" or config.at("logo-scale").at("position") == "leftright") + if show-left { + columns.push(18pt) + items.push(_logo-scale-content(config, alignment.at("seq-type"), subfamily: subfamily)) + } + columns.push(auto) + items.push(_logo-table(alignment, config, segment, name-width, num-width, cell-width, subfamily: subfamily)) + if show-right { + columns.push(18pt) + items.push(_logo-scale-content(config, alignment.at("seq-type"), subfamily: subfamily)) + } + table(columns: columns, inset: 0pt, stroke: none, column-gutter: 2pt, row-gutter: 0pt, ..items) +} + +#let _legend-entry-table(config, items) = { + if items.len() == 0 { + return none + } + let cells = () + for item in items { + cells.push(box(width: 10pt, height: 10pt, fill: resolve-color(item.at("bg")), stroke: none)[]) + cells.push(text(.._text-params(config, "legend", fill: resolve-color(config.at("legend").at("color"))))[#_text-string(config, "legend", item.at("label"))]) + } + move(dx: config.at("legend").at("dx"), dy: config.at("legend").at("dy"))[ + #table(columns: (10pt, auto), inset: (x: 2pt, y: 1pt), stroke: none, column-gutter: 4pt, row-gutter: 2pt, ..cells) + ] +} + +#let _legend-block(config, items: ()) = { + if not config.at("legend").at("show") { + return none + } + if config.at("shading").at("mode") == "functional" { + let option = config.at("shading").at("option", default: none) + let mode = if option == none { config.at("functional-default") } else { option } + if not config.at("functional-groups").keys().contains(mode) { + return none + } + let functional-items = () + for group in config.at("functional-groups").at(mode) { + functional-items.push((label: group.at("name"), fg: group.at("fg"), bg: group.at("bg"))) + } + return _legend-entry-table(config, functional-items) + } + _legend-entry-table(config, items) +} diff --git a/packages/preview/typshade/0.1.3/justfile b/packages/preview/typshade/0.1.3/justfile new file mode 100644 index 0000000000..16f44b59bc --- /dev/null +++ b/packages/preview/typshade/0.1.3/justfile @@ -0,0 +1,64 @@ +TOML_FILE := "typst.toml" + +get_value_from_toml key: + #!/bin/bash + grep "{{key}}" {{TOML_FILE}} | sed -E 's/.*= "(.*)"/\1/' + +get_local_package_dir: + #!/bin/bash + if [[ "$OSTYPE" == "darwin"* ]]; then + # macOS + echo "$HOME/Library/Application Support/typst/packages" + elif [[ "$OSTYPE" == "linux-gnu"* ]]; then + # Linux + echo "${XDG_DATA_HOME:-$HOME/.local/share}/typst/packages" + elif [[ "$OSTYPE" == "msys"* || "$OSTYPE" == "cygwin"* ]]; then + # Windows + echo "$APPDATA/typst/packages" + else + echo "Unsupported OS" + exit 1 + fi + +install: + #!/bin/bash + if ! command -v typst &> /dev/null; then + echo "Error: Typst is not installed. Please install it before running this recipe." + exit 1 + fi + + PACKAGE_NAME=$(just get_value_from_toml name) + PACKAGE_VERSION=$(just get_value_from_toml version) + LOCAL_PACKAGE_DIR=$(just get_local_package_dir) + TARGET_DIR="$LOCAL_PACKAGE_DIR/local/$PACKAGE_NAME/$PACKAGE_VERSION" + + mkdir -p "$TARGET_DIR" + + echo "Copying files to $TARGET_DIR..." + + cp {{TOML_FILE}} "$TARGET_DIR" + + cp *.typ "$TARGET_DIR" + + if [ -d "internal" ]; then + cp -r internal "$TARGET_DIR" + fi + + [ -f "README.md" ] && cp README.md "$TARGET_DIR" + [ -f "LICENSE" ] && cp LICENSE "$TARGET_DIR" + + echo "Package $PACKAGE_NAME version $PACKAGE_VERSION has been installed." + +clean: + #!/bin/bash + PACKAGE_NAME=$(just get_value_from_toml name) + PACKAGE_VERSION=$(just get_value_from_toml version) + LOCAL_PACKAGE_DIR=$(just get_local_package_dir) + TARGET_DIR="$LOCAL_PACKAGE_DIR/local/$PACKAGE_NAME/$PACKAGE_VERSION" + + if [ -d "$TARGET_DIR" ]; then + rm -rf "$TARGET_DIR" + echo "Directory $TARGET_DIR has been removed." + else + echo "Directory $TARGET_DIR does not exist." + fi \ No newline at end of file diff --git a/packages/preview/typshade/0.1.3/lib.typ b/packages/preview/typshade/0.1.3/lib.typ new file mode 100644 index 0000000000..e836668b9e --- /dev/null +++ b/packages/preview/typshade/0.1.3/lib.typ @@ -0,0 +1,15 @@ +// Copyright (C) 2026 Eito Yoneyama +// SPDX-License-Identifier: GPL-2.0 + +#import "internal/interface/annotations.typ": * +#import "internal/interface/analysis.typ": * +#import "internal/interface/controls.typ": * +#import "internal/interface/data.typ": alignment-data, parse-alignment +#import "internal/interface/inspect.typ": * +#import "internal/interface/presets.typ": shade-preset, shade-theme, visual-theme +#import "internal/interface/recipes.typ": * +#import "internal/interface/selection.typ": * +#import "internal/interface/shade.typ": * +#import "internal/interface/shortcuts.typ": * +#import "internal/interface/tracks.typ": * +#import "internal/model/palette.typ": resolve-color, scale-color diff --git a/packages/preview/typshade/0.1.3/typst.toml b/packages/preview/typshade/0.1.3/typst.toml new file mode 100644 index 0000000000..7ff83ea8ab --- /dev/null +++ b/packages/preview/typshade/0.1.3/typst.toml @@ -0,0 +1,11 @@ +[package] +name = "typshade" +version = "0.1.3" +entrypoint = "lib.typ" +authors = ["Eito Yoneyama"] +license = "GPL-2.0-only" +description = "Visualize multiple-sequence alignments for bioinformatics." +compiler = "0.14.0" +repository = "https://github.com/rice8y/typshade" +keywords = ["bioinformatics", "alignment", "sequence", "visualization"] +categories = ["visualization", "components"]