Release Notes
Version 1.1
v1.1.0 (2026-09-10)
This release substantially expands the feature-engineering surface: a unified feature-preprocessor family (embedding / structure / annotation sources), a numerical CPP mode, a configuration-sweep wrapper, sequence-window sampling, site-localization metrics, and an opt-in golden-pipeline API.
Added
Data Handling
EmbeddingPreprocessor: Per-residue protein language model (PLM) embeddings.encodenormalizes raw embeddings into a[0, 1]per-residuedict_num(minmax/quantile/sigmoid) forrun_num();build_scales/build_catcollapse them into pseudo-scales forrun().fetch_embeddings([embed]extra) downloads a curated PLM (ESM-2, ESM-1b, ProtT5, ProstT5) from the Hugging Face Hub and computes per-protein (mean/max/cls pooling) or per-residue embeddings;pool_embeddingsreduces per-residue arrays to per-protein vectors. The new[embed]extra isolates the heavytorch/transformersdependencies.StructurePreprocessor([pro]): Converts PDB / CIF / AlphaFold files (and PAE sidecars) into[0, 1]-normalized per-residue tensors (get_dssp,encode_dssp,encode_pdb,encode_pae,get_domains,encode_domains,encode,build_scales,build_cat).encodeis a single feature/backend router that dispatches each requested feature key to its owning encoder and merges the outputs into onedict_num, so callers no longer need to know the DSSP / PDB / PAE / domain split. Failure isolation is per-feature: an unavailable feature (e.g.depthwithout the externalmsmsbinary) or a per-entry encoder error now fills only that feature’s column(s) with NaN, keeps every other feature, and emits one actionableUserWarning— instead of NaN-ing the whole protein (on_failure='raise'still raises).AnnotationPreprocessor([pro]): Fetches UniProt (or ingests user / predictor) per-residue PTM and functional-site annotations and encodes them into tensors (fetch_uniprot,ingest,register_feature,encode,build_scales,build_cat,to_df_seq).combine_dict_nums: Concatenates per-residue tensors (embedding / structure / annotation) along the feature axis into one combined
CPP.run_numinput.get_labels: Derives a binary
intlabel vector from a sequence DataFrame’s label column (positive_labelmapped to1, everything else to0) — the single-call form of the recurring(df[col] == x).astype(int).to_numpy()expression.get_provenance(): An opt-in, JSON-serializable plaindictrecording how a run can be reproduced. Its one field that external code cannot easily recover is the effective resolved seed —random_stateis resolved through the same check the tools use, so the record reports the seed that actually takes effect, including whenoptions['random_state']overrides the value passed at the call site. Alongside it: adeterministicflag,aaanalysis/ Python / key-dependency versions, the git commit when resolvable (Nonefor a regular install), and an optional stablesha256fingerprint of the input viadata. It is opt-in only: nothing attaches it to any output, no return type changes, and default results stay byte-identical plain numpy / pandas. The record carries no timestamp or hostname — every field is something that can change a result, which is what lets two records be compared as a reproducibility key. No new dependency.combine_dict_nums(): Concatenates per-residue tensors (embedding / structure / annotation) along the feature axis into one combinedrun_num()input.pad_parts(): Pads the sequence-part columns of adf_partsDataFrame to a uniform length with a gap symbol (lengthtarget or each column’s per-part max; N-terminal, C-terminal, or symmetricboth). The selectedlist_partscolumns are padded (default all) and a padded copy is returned (non-selected columns and the index unchanged; input never mutated). Enables analyzing short, variable-length parts at a finer, uniform resolution via pad →CPP(accept_gaps=True) → larger uniformn_split_maxthan the shortest real part allows.load_dataset(): Every bundled dataset now carries a human-readablegenecolumn immediately afterentry— the UniProt gene symbol for the domain datasets (DOM_GSEC/DOM_GSEC_PU) and a positionalname_<row>placeholder for the amino-acid / sequence datasets (whose entries are synthetic). All other columns are byte-identical. Thegenecolumn lets asampleselector resolve by gene symbol:get_seq_kws()(and thesample_kwsplot path) now consult the optionalgene/display_namecolumns ofdf_seq(order:entry→gene→display_name→name), sosample="APP"resolves onDOM_GSEC.
Feature Engineering
SequenceFeatureTransformer: A scikit-learn transformer (BaseEstimator+TransformerMixin) that wraps theget_df_parts->run()->feature_matrix()chain so CPP feature selection happens on the training fold only:fit(X, y)selects features from adf_seq(ordf_parts) + labels and stores them (features_/df_feat_), andtransform(X)applies the same features -> the numeric matrix. Dropped into asklearn.pipeline.Pipeline(orsklearn.model_selection.cross_val_score()), the test fold never influences which features are chosen — the leak-free counterpart of selecting on the full labeled set. Follows the scikit-learn estimator contract (cloneable, validation infit, learned state with a trailing underscore) and supportsget_feature_names_out/set_output(transform="pandas"). Core (no new dependency; scikit-learn is already required).CPPGrid:Tool-style wrapper (run+eval) that runs a parallel grid sweep ofCPPconfigurations in one call; configurations differing only inn_filtercollapse into a single run.eval(sort_by=...)scores the configurations (avg_ABS_AUCby default) best-first.run_num(): Numerical mode sourcing per-residue values from a pre-sliced tensor (dict_num_parts) instead of an amino-acid → scale lookup — embedding / structure / annotation features through the same pipeline and output schema asrun().run_composit(): Composition mode — build adf_featof composition features (iFeature-style descriptors [Chen18]) scored with CPP’s discriminative statistics.composition="aac"(amino-acid composition) is positional CPP — a one-hot identity scale set with the whole-partSegment(1,1)split, so it yields<PART>-Segment(1,1)-<AA>features with positions drawn by the feature map.composition="dpc"(dipeptide) /"kmer"(generalk) are non-positional (a k-mer is an adjacent-tuple property, not a per-residue scale): the20 ** kk-mers are scored and filtered by adjusted AUC (topn_filter), a min-occurrence guard (min_count), and optional correlation dedup (max_cor). The composition matrices themselves come fromkmer_composition()(which documents the compositional approaches).CPP bootstrap / stability annotation (
CPPconstructor:bootstrap,bootstrap_kws): Opt-in resampling-based stability annotation, a thin wrapper applied uniformly byrun(),run_num(), andrun_composit(). Withbootstrap=Truethe data is resampledbootstrap_kws['rounds']times (bootstrap_kws['resample']='reference'fixes the test group and resamples only the reference group; also'both'/'test'; per-group draw sizebootstrap_kws['frac'], with replacement) and re-selected each round to score how often each feature is selected, then the ordinary full-data run is returned with a ``selection_frequency`` column (0 to 1) added. The selected features are exactly those of a normal run (n_filterstays the selection criterion);selection_frequencyflags which are reproducible under resampling — a trust / interpretability aid, not a change to the list or accuracy. The tuned config lives in onebootstrap_kwsdict (keysrounds/resample/frac, parallel tosplit_kws);bootstrap=Truedefaults todict(rounds=20, resample='reference', frac=0.8)and any omitted key falls back to its default. The defaultbootstrap=Falseis byte-identical to previous versions. Reuses the constructorrandom_state.CPP.run ``redundancy=’legacy’|’exact’`` (also
run_num()): Opt-in position-overlap criterion for the redundancy-reduction step. The default'legacy'is byte-identical to previous versions (published signatures stay reproducible);'exact'compares the actual residue positions — an interpretability enhancement (a more concentrated signature, fewer redundant subcategories) that does not change predictive performance. For a stronger, more efficient reduction, seesimplify().CPP.simplify ``candidate_search=’fast’``: Opt-in heuristic capping the candidate scales evaluated per feature, for a large speed-up on big scale pools (mainly
greedy). The default'exact'reproduces the previous result;'fast'is statistically equivalent (kept-feature Jaccard ≥ 0.95, ΔavgABS_AUC ≤ 0.005 on the canonical data).SequenceFeature.get_labels_ovr / get_labels_ovo: Convert multi-class
labelsinto binary sets forCPP— one-vs-rest (all samples kept) or one-vs-one (per class-pair, each pair’s value source row-matched).SequenceFeature.get_labels_quantile / get_labels_tiered: Discretize a continuous target into binary
labels— a single quantile cut, or a fixed positive set swept against stepwise-lowered negative cuts (each tier row-matched).SequenceFeature.scale_composition: Scale-composition baseline featurizer that turns sequences + scales into a
(n_seq, n_scales)matrix by averaging each scale over a sequence span (list_parts=None→ wholejmd_n+tmd+jmd_c), dropping missing / non-canonical residues — the sequence’s mean profile in scale-space (the scale-based analogue of amino-acid composition). The no-positional-split baseline to compare againstfeature_matrix/ CPP; optionalreturn_df=Truefor a labeled frame.feature_matrix(): Turnsrun_num()-selected features back into a model matrixX— the numerical analog offeature_matrix(). Reconstructs eachPART-SPLIT-SCALEvalue from the per-residue tensors indict_num_parts, with per-part lengths taken fromdf_parts(the same length sourcerun_num()uses), re-applying the split to the part’s residue axis rather than the JMD-offsetpositionsdisplay numbering.Xis therefore byte-identical to the valuesrun_num()computed and preserves the per-residue context that per-AA-averaged sequence features discard.SequenceFeature.aa_composition: Amino-acid-composition (AAC) baseline featurizer that turns sequences into a
(n_seq, 20)matrix — the fraction of each of the 20 canonical amino acids (ut.LIST_CANONICAL_AAcolumn order) over a sequence span (list_parts=None→ wholejmd_n+tmd+jmd_c), dropping gaps / non-canonical residues so each row sums to 1. Fully vectorized; the no-positional-split residue-frequency baseline to compare againstfeature_matrix/ CPP; optionalreturn_df=Truefor a labeled frame.SequenceFeature.dipeptide_composition: Dipeptide-composition (DPC) baseline featurizer that turns sequences into a
(n_seq, 400)matrix — the fraction of each of the 400 ordered adjacent canonical amino-acid pairs (AA, AC, ..., YY) over a sequence span, dropping gaps / non-canonical residues before pairing (adjacencies span dropped residues and cross concatenated part boundaries); each row with at least two canonical residues sums to 1. Captures local sequential order that plain composition discards; fully vectorized; optionalreturn_df=Truefor a labeled frame.SequenceFeature.kmer_composition: General k-mer-composition baseline featurizer — the fraction of each of the
20 ** kordered overlapping k-mers of adjacent canonical residues over a sequence span, a(n_seq, 20 ** k)matrix (columns initertools.product(ut.LIST_CANONICAL_AA, repeat=k)order).kselects the composition:k=1is amino-acid composition (identical toaa_composition),k=2dipeptide composition (identical todipeptide_composition), and higherk(up to 4) captures longer local sequential order. Same non-canonical-dropping, gap-free-span, each-row-sums-to-1 semantics as thek=1/k=2special cases; fully vectorized (onebincountover base-20 k-mer codes); optionalreturn_df=Truefor a labeled frame.return_scales=Truealso returns the CPP-ready(df_scales, df_cat): fork=1the(20, 20)one-hot identity scale set + amino-acid-classdf_cat(feed torun()with a whole-partSegment(1,1)split to get amino-acid composition as a realdf_feat/ feature map); fork>=2df_scalesisNone(a k-mer is not a per-residue scale) anddf_catcategorizes the k-mers by residue class.SequenceFeature.acc: Order-aware scale auto-covariance (ACC) baseline featurizer — for each scale and lag
k(1 .. n_lag) the mean-centered auto-covariance of that scale’s values along a sequence span, a(n_seq, n_scales * n_lag)matrix in lag-major column order (list_parts=None→ wholejmd_n+tmd+jmd_c), dropping gaps / non-canonical residues before the covariance. The lag extension ofscale_composition(same default scales, span, and NaN handling): where the scale mean is order-blind,acckeeps short-range sequential order in scale-space while staying position-agnostic — the natural middle point betweenscale_compositionand CPP for a “baseline vs CPP” comparison. Only the auto-covariance over the full default scales is computed (no cross-covariance,n_scales * n_lagcolumns). A lag whose span is too short (N - k < 1) isNaN; fully vectorized (segment sums, no per-sequence loop); optionalreturn_df=Truefor a labeled frame (f"{scale}_lag{k}"columns).SequenceFeature.get_df_parts_from_windows: Assemble a reference
df_partsfrom per-part window sets (e.g.AAWindowSampler.sample_syntheticoutput).SequenceFeature.get_seq_kws: Return one protein’s
{jmd_n_seq, tmd_seq, jmd_c_seq}get_df_parts_from_windows(): Assemble a referencedf_partsfrom per-part window sets (e.g.sample_synthetic()output).get_seq_kws(): Return one protein’s{jmd_n_seq, tmd_seq, jmd_c_seq}as a ready-to-splatseq_kwsdict (by entry or position), parts taken fromdf_partsso the residues stay bound to the feature geometry — removing the manual slicing glue when feedingprofile()/feature_map(e.g. sample-level SHAP plots).``sample_kws`` bundle on CPPPlot plots:
feature_map(),heatmap(), andprofile()take a structuredsample_kws=dict(sample, df_seq, df_parts)— the bundled alternative to providing the TMD-JMD sequences directly.sampleaccepts anentryname or a value from the optionalnamecolumn ofdf_seq(str), or a row position (int); anameis resolved to itsentry, and a selector that matches nothing or is ambiguous (a duplicatedentryor anameshared by several entries) raises aValueError. It resolves that sample’s sequence band (and, for the SHAP variants, the per-samplefeat_impactcolumn) fromdf_partsand overrides any explicitly passedtmd_seq/jmd_n_seq/jmd_c_seq. The displayed sequence stays faithful to thedf_partsthe features map to, so its own lengths set the grid geometry (tmd_len/jmd_n_len/jmd_c_lenapply only when no sequence is shown). See the keyword-dict parameters overview in the docstring guide.get_feature_descriptions(): One standardized, human-readable sentence perPART-SPLIT-SCALEfeature id (region + split + AAontology scale name / category). Additive (the'feature'id is unchanged); fills an optional'feature_description'column.pre_select_scales(): Metadata-only pre-filter that drops scales by AAontologycategory(cat_out) /subcategory(subcat_out) viadf_cat— the preparation step beforeselect_scalesorfilter_coverage(no clustering).select_scales(): Wrapper aroundfit()that returns the redundancy-reduced scale subset (one medoid per cluster) directly, ready forCPP.select_proteins(): Protein-level redundancy reduction over a per-protein feature matrixX— clusters proteins, selects one medoid per cluster, annotatesdf_seqwithcluster/is_representative/dist_to_rep— the numerical counterpart tofilter_seq().AAclustPlot.centers / medoids accept ``df_scales``: Pass scales via
df_scales(transposed internally) instead ofcenters(np.array(df_scales).T, ...); pass proteins / embeddings / CPP features viaX(used as-is). The explicitXsignature is unchanged.
Prediction
ReliabilityModel: Per-sample prediction reliability — quantifies how much to trust a prediction, separately from the score itself (a model can be confident about a0.55and worthless about a1.0out-of-distribution score). Wraps a fitted predictor (anAAPred, aTreeModel, or any scikit-learn classifier) plus its training data and reports, per sample: stability (ensemble/bootstrapscore_stdand a confidence interval), an applicability-domain out-of-distribution signal (k-NN distance, Mahalanobis, leverage →ood_score/in_domain), calibrated sharpness (margin/entropy), a marginal split-conformal prediction set that can abstain, and a headlinereliableflag (in-domain, stable, and a confident conformal singleton).fit/predict/eval; core scikit-learn only, no new required dependency.ReliabilityModelPlot: VisualizesReliabilityModeloutput — a per-sampleranking(each prediction’s score with its uncertainty interval, colored by trust status), a calibration curve (reliability_diagram), the out-of-distribution score distribution (ood_hist), and a score-vs-OODtrust_mapcolored by thereliableflag.ModelEvaluator: Rigorous, model-agnostic evaluation harness for a feature matrixXandlabels.runscores one or more scikit-learn models by repeated stratified cross-validation (multi-seed mean/std overn_cv * n_roundsfolds) with a percentile bootstrap confidence interval of the mean per (model, metric);evalcompares the models pairwise on the same folds with a signeddelta(e.g. ΔMCC), a bootstrap CI on the paired differences, and a two-sided Wilcoxon signed-rankp_value. Metrics addmcc(Matthews correlation coefficient) to the prediction metric set; both outputs are byte-identical underrandom_stateand reusecomp_bootstrap_ci()— no new dependency.ModelEvaluatorPlot: VisualizesModelEvaluatoroutput —scoresdraws grouped confidence-interval bars of the cross-validated scores per (model, metric), andcomparedraws the paired comparison as signed delta bars with CI whiskers and significance stars.eval(): Newbaselineoption to compare the bound (CPP) features against simple, non-positional baselines built internally fromdf_seq—'scale'(scale_composition()),'aac'(aa_composition()),'dpc'(dipeptide_composition()), and'acc'(acc(), the order-aware scale auto-covariance);baseline=Trueselects the scale baseline. Each baseline is cross-validated with the same models and folds and appended todf_evalunder a new leadingfeaturescolumn ('cpp'for the bound rows), so the whole “CPP vs baseline” comparison comes from one call. Purely additive: withbaseline=None(default)df_evalis byte-identical to before (nofeaturescolumn).eval()(bar plot) reads thefeaturescolumn as the hue, so it draws thecppand baseline bars side by side instead of averaging them.eval(): Newcvoption to cross-validate with an arbitrary scikit-learn splitter (e.g.LeaveOneOut()) instead of the integern_cvfolds. Unliken_cv, a splitter is not capped at the smallest class count, soLeaveOneOutworks on small, imbalanced sets. Its rows are scored by a new'cv_pooled'principle: every held-out prediction is pooled and each metric is applied once on that pooled vector (reproducingmetric(labels, cross_val_predict(estimator, X, labels, cv=cv))), rather than averaging a degenerate per-fold score — the correct principle when a single-sample test fold makes per-fold averaging meaningless.score_stdisNaNforcv_pooled(a single estimate). Purely additive: withcv=None(default)df_evalis byte-identical to before.predict_oof(): New method returning cross-validated out-of-fold per-sample scores for the training set — each sample is scored by models fit on the folds that exclude it (stratified k-foldcross_val_predict), so the training-set scores are free of the optimistic in-sample bias that scoring them withpredict()would incur. Every configured model is cross-validated independently and the per-model out-of-fold scores are averaged, returning the samescore/score_stdshape aspredict()(mean over the ensemble, std across models). Likeeval()it cross-validates the constructor models and needs no priorfit(); deterministic underrandom_state.score_to_group(): New stateless staticmethod mapping prediction scores to an ordered categorical of named confidence bands (thresholdsdelimit the bands,labelsnames them low-to-high; each threshold is an inclusive lower bound).score_range('percent'/'proba') bounds the thresholds so probabilities and percentages can’t be silently mixed;NaNscores stay missing and apd.Seriesinput keeps its index. It is the single source of truth for the band boundaries used bypredict_group()(band=True), so a table and its plot always agree.eval(): Newkind='heatmap'that renders any 2D score grid (rows x columns are the two sweep axes) as a square annotated heatmap and boxes the best cell(s) with a full-cell frame —highlightselects how many (a positive int for the top-N,"max"/"min", an explicit(row, col)/ list, orNone);vmin/vmax/cmap/cbar_labelstyle the color scale and its tick-side-edged colorbar. One call for the recurring “grid of scores -> seaborn heatmap -> mark the best configuration” block.predict_group(): Newkind='rank_scatter'— a per-protein rank scatter (proteins ranked by their maximum score and colored by group, with optional threshold lines), the standard sanity check for a deployed per-protein predictor. Plus a newband=Truemode forkind='hist'that colors each bar by the confidence band it falls into (delimited bythresholds) instead of by classlabels— for scoring unlabeled candidates. Both additions are purely additive; existing default outputs are unchanged.
Explainable AI
ShapModel — accession-based interface (
[pro]):fitaccepts entry-keyed soft labels (fuzzy_labels={'P05067': 0.6}) together withdf_seq;add_feat_impact/add_sample_mean_difacceptdf_seqand asamplesparameter taking row positions or entry names. The array-labelspath is unchanged;sample_positionsis a deprecated alias forsamples(removed in 1.2.0).ShapModel — unbiased fuzzy estimator, now the default (
[pro]):fitgainsfuzzy_aggregation, defaulting to the new'interpolate'estimator. It weights a soft label by exactlyp— fitting at 0 (S0) and at 1 (S1) and blendingp * S1 + (1 - p) * S0— the unbiased alternative to the biased threshold sweep, which stays available as a first-class option viafuzzy_aggregation='threshold'. Forinterpolate,n_rounds(default5) is a speed/stability dial:1is the fast exact two-fit estimate (~2x faster than the threshold default on the same cell),5adds light Monte-Carlo averaging, and the mean converges (run-to-run spread below ~5%) aroundn_rounds ≈ 15–20; a fixedrandom_statekeeps every run reproducible.CPPStructurePlot([pro]): Paints per-residue CPP / CPP-SHAP feature impact onto an interactive 3D protein structure, rendered with py3Dmol (no matplotlib structure fallback — the cartoon is always a real 3D view).map_structure( df_feat, pdb=...)(oruniprot=...to auto-fetch the AlphaFold model) returns aStructureView(show/write_html/_repr_html_). Supports an'impact'red-white-blue ramp and a'plddt'AlphaFold-confidence mode, withwhole/fade/zoomfocus. By default each feature’s full impact is painted on every residue it spans (app-fidelity colouring);normalize_by_span=Trueswitches to the span-normalized sum used byprofile()and thefeature_map()top per-position bar.plot_combinedreturns aCombinedViewshowing the py3Dmol cartoon next to thefeature_map()image (write_htmlexports the pair;savefig(path)saves the feature-map panel as a static PNG / PDF for papers — the 3D cartoon is interactive and has no headless image), reproducing the deployed cleavage app’s signature layout.interactivereturns a live ipywidgets explorer (added to the[pro]extra) where a site slider drives a userpredictorand repaints the linked 3D structure andfeature_map()together (debounced), the notebook-native version of the app’s per-site explore loop. A highlight (position) slider links the two panels live: picking a residue lights it up in the 3D cartoon and marks its feature-map column without re-predicting, and with theipympl(%matplotlib widget) backend the feature map becomes clickable for the same highlight (ipymplis optional — the slider is the always-present link, no extra dependency).plot_linkedreturns aLinkedView— a self-contained HTML where hovering a feature-map column highlights the corresponding residue in the 3Dmol cartoon (the app’s signature interaction);write_htmlexports it as a standalone, shareable page.explore(df_feat, sequence, df_seq=..., labels=..., model=...)is the integrated one call: it builds a built-in per-site predictor (compute the query window’s values for the fixed feature set, predict the probability, attach the per-site SHAP impact via a defaultShapModelrefit — norun()rediscovery) and dispatches to a selectableoutput('widget'/'html'/'static');modeltakes a name ('rf'/'svm'/'log_reg'), an estimator, or a list, and a custompredictor=(sequence, p1) -> df_featremains the escape hatch. Withoutput='html', passingsites=[...]bakes a multi-site live standalone page: a client-side JS slider switches the pre-computed prediction per P1 (feature map + structure restyle) with no kernel, keeping the column-residue linking (warned past 40 sites, hard-capped at 200).
PU Learning
dPULearn.fit — positives/unlabeled split input: for the common positive / unlabeled setup,
fitnow acceptsX_posandX_unlabeledseparately (an alternative toX+labels) instead of stacking them by hand and building a1/2label vector. After fitting, the newdPULearn.mask_neg_attribute holds the boolean mask of reliable negatives — over the rows ofX_unlabeledin the split mode, overXotherwise (equal to the manuallabels_[len(X_pos):] == 0result exactly).fitstill returnsselfand the existingfit(X, labels=...)path is unchanged.project(): Projects held-out samples from the same feature space into the fitted PC space (thePCicolumns ofdf_pu_) after PCA-based identification, so new proteins can be placed alongside the identified negatives.methodselects the reconstructed linear map —'lstsq'(default, affine least-squares) or'components'(exact PCA-geometry map); both are exact on the fitted samples and interpolate for new ones.pca()gainsdf_pu_add/names_add/colors_addto overlay one or more projected groups (a one-call four-group PCA); the default (df_pu_add=None) output is unchanged.
Sequence Analysis
AAWindowSampler: Samples fixed-length sequence windows for PU-learning and hard-negative-mining workflows (sample_same_protein,sample_different_protein,sample_motif_matched,sample_synthetic).scan_motif()([pro]): Scans candidate proteins for statistically significant PWM occurrences via MEME/FIMO, complementing the pure-Pythonsample_motif_matched()sampler.
Protein Engineering
SeqOpt — multi-objective protein engineering (core; only
mode="impact"needsaaanalysis[pro]): A newSeqOptoptimizer (withSeqOptPlot) performs machine-learning-guided directed evolution of one wild-type — searching the Pareto front across several objectives at once, with a model-boundSeqMutas the fitness engine and a re-implementation of NSGA-II for selection (this is protein engineering, not de novo design). Two guidance modes:mode="impact"refitsShapModeleach generation under fuzzy labeling to target the strongest-feat_impactresidues;mode="importance"walks positions by staticfeat_importance. The evolutionary toolbox is a complete pure-Python re-implementation (DEAP is a dev/test-only parity oracle; runtime stays DEAP-free):crossover(uniform / one- / two-point),mutation(substitution / shift),variation(varAnd / varOr),survival((mu+lambda) / (mu,lambda) / eaSimple),constraints(delta / closest-valid penalty), a single-objective Hall of Fame (hall_of_fame_), and a memory-bounded (chunked) vectorized non-dominated sort. Objectives accept anycallable(sequence) -> float(an external scikit / torch model or sequence-level tool / web API), cached per variant.runreturnsdf_pareto(objective columns +rank+crowding) backed by a cumulative Pareto archive;evalreports hypervolume / front size / spread / convergence. Visualization:SeqOptPlotcoverspareto_front(2-D / 3-D),parallel_coordinates,convergence(hypervolume + spread + per-objective best/mean/worst band),hypervolume,mutation_map(front substitution-enrichment heatmap) andgenealogy(mutational-lineage tree). Reproducible viarandom_state/seed.SeqMut model-guided mode (ML-guided directed evolution):
SeqMutis optionally model-aware — binding a fitted classifier (SeqMut(model=..., target_class=...), any object withpredict_proba) makesscan/suggest/mutatereportdelta_pred(the prediction-score shift in percentage points) andsuggestrank by it. Without a model,SeqMutstays the deterministic, model-free ΔCPP tool.combine(): Scores combined multi-mutation variants — several point mutations applied to one sequence and evaluated as a single design.SeqMutPlot:mutation_landscaperenders thedelta_predprediction-shift mutation-scan heatmap; newvariant_impact(ranked-variant bar) andepistasis(pairwise non-additivity) plots.
Metrics
comp_per_protein_ap(): Per-protein average precision for site-localization ranking, with an optionaltolerance=±kvariant for positional jitter.comp_detection_metrics(): Recall / precision / F1 / MCC at a fixed score threshold, pooled across per-residue predictions.comp_bootstrap_ci(): Seeded percentile confidence interval over a per-protein metric vector (returns{'mean', 'ci_low', 'ci_high'}).comp_smooth_scores(): Peak-preserving (max(smoothed, raw)), NaN-aware smoothing of per-residue score tracks.
Plotting
cell_size on
feature_map()/heatmap()/profile(): a(width, height)inches tuple that holds every grid cell at that exact physical size — the figure shrinks for a small grid and grows for a large one, and nothing clips the figure edge — for any sequence length or number of scale subcategories.figsizeseeds the layout;cell_sizesets the cell (the profile uses only the width). The cumulative-importance bar strips (top per-position, right per-subcategory) are sized in grid-cell units and clamped to a min/max cell range, so they lock to a near-constant physical size instead of ballooning on dense grids or vanishing on sparse ones; the importance-axis maximum value sits left of the right spine on a short strip and right of it on a tall one (the standard look), and the[%]suffix is dropped from the heatmap-only label so both variants read the same.seq_size on
feature_map()/heatmap()/profile()gains"auto"(default): it fits the residue letters to the grid cell and steps them down for a short TMD, so a fixed cell keeps the sequence consistent too. A value in(0, 1]sets the letter height to that fraction of the cell, and a value> 1is an absolute font size in points; the letters never overlap at any size.fontsize_labels on
feature_map()/heatmap()gains"auto", which tracks theplot_settingsfont scale, caps at about 13 pt, and shrinks on overlap so the scale-subcategory rows never collide.COLOR_SAMPLES_POS / COLOR_SAMPLES_NEG / COLOR_SAMPLES_UNL / COLOR_SAMPLES_REL_NEG: Public, named constants for the canonical sample-group colors (positive / negative / unlabeled / reliable-negative). They equal the
plot_get_cdict("DICT_COLOR")["SAMPLES_*"]values exactly, so a named constant replaces indexing the color dict by string key.options[‘plot_settings’]: Opt-in, session-persistent
plot_settings(). Assign a dict ofplot_settings()keyword arguments (e.g.aa.options['plot_settings'] = {'font_scale': 1.2, 'weight_bold': True}) and every subsequent*Plotfigure adopts the publication style automatically, soplot_settings()need not be repeated before each plot. The default (None) applies no implicit styling and keeps plot output byte-identical; the style is (re)applied only when the option’s value changes, so an explicitplot_settings()call takes precedence for the figures drawn after it.
Golden Pipelines
aaanalysis.pipe (
ap): A second, opt-in convenience API of stateless, one-call golden pipelines over the AAanalysis primitives (import aaanalysis.pipe as ap).ap.find_features: Staged, interpretable CPP AutoML search. Stage 1 cross-validates the full Cartesian Part × Split × Scale grid and ranks each axis by its marginal-mean impact; Stage 2 refines the single highest-impact axis against
n_filter; Stage 3 refines the winning feature set (simplify()+ recursive feature elimination, each kept only if it is not Pareto-dominated). Selection is multi-objective: within each stage the Pareto-optimal-then-simplest configuration across allmetricwins, scored by the averaged cross-validated performance of one or moremodels. The winner is ranked by tree-based importance and drawn as the feature map. Thesearchgrade scopes the effort ("fast"is byte-identical to the explicit single-CPP path); it returns(df_feat, ax, df_eval)whereaxalso carries the publication eval figures (ax.eval) anddf_evalhas one<metric>_mean/_stdcolumn per metric plusstage/is_pareto/rank/is_selected.ap.find_features: New
selection_scope="global"|"fold"for an opt-in honest nested cross-validation."global"(default) is unchanged — CPP selects on the full labeled set, so the scores are an in-sample (optimistic) ranking signal — and remains byte-identical."fold"re-selects CPP features on the train split only inside every fold of every configuration score (Stages 1–2 and the simplify refine), sodf_evalreports held-out (typically lower) generalization estimates instead. The winner’s second-step refinement (simplify()+ recursive feature elimination) runs on all data in both scopes, so no refinement capability is lost in"fold"; the returneddf_featis the winner refit on all data.df_evalgains aselection_scopecolumn, and aUserWarningflags the costly"fold"+search="exhaustive"combination.ap.explain_features: New opt-in
add_sample_mean_dif(+label_ref) that enriches the returneddf_featwith per-sample mean-difference columnsmean_dif_'name'(each explained sample’s feature value minus thelabel_refgroup average) alongside the SHAPfeat_impact_'name'columns, for the same sample(s) — reusingadd_sample_mean_dif()so compute stays separate from plotting. Defaultadd_sample_mean_dif=Falseleaves the output unchanged.ap.predict_samples: Trains and cross-validates every
(feature set × model)combination over onedf_seqin a single call, returning the refit predictors and a tidy comparison table. Withplot=True(the default) it now also draws the model comparison bar plot (hue = model, one bar group per metric, cross-validationstderror bars) and returns itsAxesin the previously-unused middle slot, completing the(results, fig, evals)symmetry withfind_features/explain_features(figsize/dict_color/baselinestyle it).ap.plot_eval: Publication-ready evaluation figures of a
find_featuressweep — the high-dimensional Part × Split × Scale grid is decomposed into a series of clean 2Dviridisheatmaps (the two most-informative axes on each panel, the least on the slice), with a shared colorbar, the selected configuration starred, plus marginal-impact andn_filterpanels. Returns the list of figures so each drops straight into a paper; also usable standalone on afind_featureseval table.
Package
aa.__version__: The installed package version is exposed at top level via
importlib.metadata.CHANGELOG.md + deprecation policy: A root
CHANGELOG.md(Keep a Changelog format) gives a terse, developer-facing index alongside these narrative notes. From v1.x onward, any rename or removal of a public symbol ships at least one minor release carrying aDeprecationWarningfirst; an internaldeprecated(reason, version_removed)decorator marks such symbols. See Versioning and Deprecation Policy inCONTRIBUTING.rst.
Documentation
Docs-version coherence: the rendered docs now say which version they document.
conf.pyderives Sphinx’sversion/releasefromaaanalysis.__version__(a single source, ultimatelypyproject.toml) instead of the hardcodedversion="latest"/release='2023'literals, which had left the pages advertising a 2023-era build while the package moved on. Any build that is not from a release tag — thelatestbranch build, a pull-request preview, or a local build — now carries an unreleased development version banner on every page, naming the version and linking tostable, so a reader (or an agent) can no longer mistake documentation of unreleased capabilities for the release they installed.Prediction tasks concept page (Usage Principles): maps a biological question to the right workflow via a task table keyed on unit of comparison and reference construction, across the residue / domain / protein levels — the front door to the Protocols catalog.
A minimal CPP analysis tutorial (
tutorial0_minimal): the shortest end-to-end loop — load a dataset, run CPP, read out the signature.Documentation navigation: the sidebar is grouped into four sections — Overview, Guides (Tutorials · Protocols · Use Cases), Reference, and Project — and the landing page gains a “You want to… / Go to” routing table; the previously unwired Comparison Harness tutorial (
tutorial6_comparison_harness) is now reachable.Use Cases guide (third Guides subchapter): each use case showcases a published study end to end from bundled data. The first, Charting γ-secretase substrates by explainable AI (
use_case1_gamma_secretase), walks the full AAanalysis pipeline of Breimann and Kamp et al., Nat. Commun. 2025 on the bundledDOM_GSEC/DOM_GSEC_PUsets: AALogo sequence logos of the three protein groups, AAclust redundancy-reduced scale sets, the CPP + TreeModel signature and feature map, dPULearn reliable-negative mining (with PCA and logo), a prediction benchmark (feature engineering × data expansion) plus a CPP/dPULearn optimization heatmap, and SHAP single-residue explanations for individual substrates (APP, N-cadherin).Standardized tutorial header box: every tool tutorial now opens with a uniform green You will learn box (Tool · Input · Output · Best used for · Related protocol · Related API), giving a one-glance answer to what tool, what goes in, what comes out, and where to go next and cross-linking the matching protocol and API reference.
Split API reference: the reference is now two pages, each listing its members directly at the top level. API documents the explicit building blocks (
import aaanalysis as aa) grouped by category; the new API (Pipelines) page documents the golden pipelines (import aaanalysis.pipe as ap), one function per pipeline. Golden pipelines are no longer mixed into the building-block page or the Tutorials section; Getting Started links both references.Tutorial gallery: the Tutorials landing page now opens with a seaborn-style grid of thumbnail cards — one real headline figure per tool tutorial (Data Loader, Scales Loader, AAclust, SequenceFeature, CPP, Data representations, dPULearn, ShapModel, Evaluation, Protein engineering) — so the tool catalog is scannable at a glance, mirroring the Protocols gallery. Each tile is rendered from the actual AAanalysis pipeline on bundled fixtures (generator:
docs/source/_artwork/thumb_scripts/make_tutorial_thumbs.py). The Protocols gallery thumbnails were also refreshed against the current CPPPlot layout so the two galleries render consistently.
Changed
AAPred: capability-based estimator validation — the constructor now requires onlypredict(hard-label prediction), so a probability-free estimator such asSVC(kernel="linear")is accepted.predict_probais validated per operation: it is required only wheneval()is asked for a probability metric (roc_auc) and by the probability-scoring paths (predict()/predict_oof()), with an actionable error naming the metric when it is missing. Estimators that supportpredict_probaare unaffected (default RandomForest paths unchanged).TreeModel: per-round seeding fix — with a fixedrandom_state(or the globaloptions["random_state"]),fit()now reseeds each round torandom_state + iso the rounds are independent. Previously every round fit identical estimators, sofeat_importance_std(andpredict_proba()’spred_std) collapsed to exactly0and rounds 2..N were wasted. Fixed-seed importances change once (degenerate → real Monte-Carlo mean with non-zero std); therandom_state=Nonedefault is unchanged.Consistent auto_font sizing:
heatmap()/profile()/ranking()now default tofigsize=Noneand honor any explicitfigsizeas a fixed size, so “explicit figsize wins” holds package-wide (matchingfeature_map()); omittingfigsizeauto-sizes as before.heatmap()/profile()gain theseq_char_fillresidue-band option already onfeature_map(), andpredict_group()(kind='rank_scatter') joinsauto_font— its width grows with the number of ranked proteins whenfigsizeis omitted.Constant-cell sizing shrinks as well as grows: on the
auto_fontpath (and whenevercell_sizeis set),feature_map()/heatmap()/profile()now size the figure so each cell hits the target exactly — a sparse grid yields a smaller figure (previously it floored at the default and the cells ballooned), a dense grid a larger one, and nothing clips at the figure edge at any size. The TMD/JMD part labels are capped in size and held a constant distance below the sequence band (they previously rode the residue-letter size and could grow huge or collide with the sequence). The bottom furniture is laid out as one compact, top-aligned row clustered just below the grid — the scale-category legend, theFeature valuecolorbar (a fixed-thickness gradient bar, no longer collapsing to a thin line when the figure shrinks) and the feature-importance legend — so it no longer scatters or overlaps the position ticks on a sparse grid. The coloured per-residue sequence cells and the scale-category sidebar render as solid, gap-free blocks (the sidebar at a readable, cell-relative width), and the subcategory row labels are lifted to the colorbar/legend size so they are no longer a step smaller than the rest — matching the cheat-sheet reference at any figure size.Uniform plot return contract: Every public
*Plotmethod now returns a single(fig, ax)pair (forwarding attribute access toax, so existingax = plot(...); ax.set_title(...)code keeps working), replacing the previous mix of shapes. Breaking change, scheduled for the next major release:centers()/medoidsreturn(fig, ax)and expose the PCA-component DataFrame on thedf_components_attribute instead of as the second return value.CPP performance: The Cython feature-matrix kernel, macOS-safe threaded
n_jobs, scale / AA-index caching, and scale / sample batching land in this release, replacing the hour-long, low-CPU CPP runs of≤1.0.3— users on those versions should upgrade. When the compiled extension is missing and CPP falls back to the pure-Python kernel, the one-time notice is now aUserWarning(visible even withverbose=False).feature_matrix(): Newbatch=parameter accepts a list ofdf_partsbuilt in a single Cython pass (faster for many small part tables).SequenceFeature.feature_matrix: New
df_seq=/list_parts=parameters builddf_partsinternally (viaget_df_parts), collapsing theget_df_parts→feature_matrixtwo-step into one call. Exactly one ofdf_parts/df_seqis required; the existingdf_parts=path is unchanged (byte-identical).get_df_parts / NumericalFeature.get_parts: New
pos-anchor mode (tmd_len=) explodes each 1-based anchor into onejmd_n/tmd/jmd_crow (entry_win).get_df_partsis also several-fold faster (vectorized; output unchanged).n_jobs: Unified parallelism convention across
CPP/CPPGrid(1serial,-1all cores,N>1exactly N,Noneoptimized), with anoptions['n_jobs']global override.feature(): Titles the plot with the feature’s human-readable description, line-wrapped viashow_title(defaultTrue) andtitle_wrap_width(default45).load_dataset verbose reporting: New
verboseparameter (defaultFalse) reports how many entries each removal step (min_len,max_len, andnon_canonical_aa='remove') drops, making the previously silent filtering observable. The returned data is unchanged; to retain every entry usenon_canonical_aa='keep'.Docstring discoverability: Surfaced previously implicit API contracts at the docstrings users read (no behavior change) — the
get_parts→run_numcall order and[0, 1]normalization contract, and a[pro]install marker on the pro classes / functions.fit(): Flexible label handling vialabel_pos/label_unl/label_negmarkers (only unlabeled samples are candidates; pre-labeled negatives are kept and never re-selected). The negative count is set by exactly one ofn_neg(the total wanted) orn_unl_to_neg(drawn directly from the unlabeled pool); output uses the package convention (1positive,0negative,2unlabeled).Pooled, optionally concurrent web fetches:
fetch_alphafold/fetch_uniprotroute every request through a pooledrequests.Sessionand accept amax_workersparameter. Concurrency is off by default (parallel requests risk HTTP-429 throttling); when enabled, results reassemble in input order, so output is byte-identical.Performance (same output): Many internal hotspots were vectorized or parallelized with byte-identical results —
AAWindowSamplerfiltering / sampling,AAclustmedoid distances, the per-feature KLD path ineval(),encode_one_hot,comp_substitution_impact(),get_sliding_aa_window, and severalStructurePreprocessorencoders (encode_pdbcontact / disulfide / pLDDT, a shared per-entry chain-pick and alignment cache,get_dssp). Public APIs and outputs are unchanged.Developer tooling: A committed
pytest-benchmarksuite (tests/benchmarks/,[bench]extra) micro-benchmarks the hot entry points as a non-gating nightly; a numerical-equivalence tolerance policy defines three tiers (T1 byte-identical, T2allcloseplus identical discrete decisions, T3 statistically-equivalent within an agreed band) for output-affecting optimizations; and an advisory pyright ratchet (.github/pyright_baseline.txt) drives the type-contract count down per subpackage (now 887, every public-API signature pyright-clean). None gate a merge or change the public API.Packaging gate: a
Packagingworkflow (.github/workflows/packaging.yml) builds the sdist + wheel with the defaultpython -m buildon every push / PR tomaster, then installs both the built wheel and the sdist into separate fresh base-deps-only venvs (no[dev]/[pro]) and asserts that everyaaanalysis.__all__symbol imports, thatpro/devsymbols degrade to an install hint when their extra is absent, and that bundled_dataresources load — across the min + max supported Python (3.10, 3.14). It catches a missing package-data file, a broken re-export, or a sdist that cannot build before a release reaches PyPI, where the editable dev matrix cannot. No public-API change.Version truth:
aaanalysis.__version__onmasteris now1.1.0and no longer collides with the published1.0.3release, so a development checkout and a released install are distinguishable — for bug reports, cached environments, and reproducibility records alike. AVersion Guardworkflow (.github/workflows/version_guard.yml) enforces the invariant on every push / PR tomaster:.github/scripts/check_version_ahead.pyfails the build unless the declared version is strictly ahead of the latest release published on PyPI (falling back to the latestvX.Y.Zgit tag offline). The version stays a hand-editedpyproject.tomlstring — deriving it from git tags was rejected to avoid.devN/+g<sha>proliferation. Release procedure gains one closing step: after publishing, bumpmasterto the next unreleased number (see Version truth inCONTRIBUTING.rst). No public-API change.Named logger for library output: all package messages now flow through
logging.getLogger("aaanalysis").print_out(ut.print_out) is a thin, permanent shim overlogger.info(...)— the function name and signature are unchanged, so every call site is unaffected. Power users can now attach handlers, capture output in pytest’scaplog, redirect it to a file, or raise/lower verbosity withlogging.getLogger("aaanalysis").setLevel(...)(or theut.set_logger_verbosityhelper). The logger level is an independent power-user control: the existingverboseflag /options['verbose']continue to gate output at the call sites exactly as before, so a globaloptions['verbose']never mutes an object explicitly built withverbose=True. A single default stdout handler reproduces the previous blue-coloured output, so on-screen behaviour is unchanged (no new dependency; stdlibloggingonly). The live progress bar keeps writing to stdout directly. No public-API change.
Changed
Module rename: the
protein_designsubpackage is nowprotein_engineering, matching its user-facing name (AAMut/SeqMut/SeqOptare amino-acid mutation and directed-evolution tools). The public classes are unchanged and imported the same way (import aaanalysis as aa→AAMut,SeqMut,SeqOptand their plot classes); only a full-path import such asfrom aaanalysis.protein_design import SeqMutmust becomefrom aaanalysis.protein_engineering import SeqMut.
Fixed
Clearer failure messages on the golden pipelines: an invalid call now names the offending input in the package’s own voice.
find_features()validateslabelsup front, so a single-class or length-misaligned label vector raises a preciseValueError(”'labels'should contain more than one different value” / “should contain N values”) instead of an opaque “produced no valid configurations” runtime error, andpredict_proba()raises a self-explaining “'X'n_features (…) should match the fitted model’s n_features” instead of scikit-learn’s internal estimator message when a feature matrix has the wrong width. The failure contract of the golden pipelines and the CPP toAAPredpath (a bareValueError/RuntimeError, or an install-hintImportErrorfor a missing[pro]dependency) is now regression-guarded by an integration test suite and, from an installed distribution, by the packaging smoke check. See Failure contracts.Source install from the sdist now builds: the published sdist previously omitted the Cython source
_filters_c/_inner.pyx, so the defaultpython -m build(which builds the wheel from the sdist) and any source install (pip install <sdist>,pip install aaanalysis --no-binary) failed to cythonize. AMANIFEST.innow ships the Cython sources into the sdist, so both paths build and import the compiled extension. The shipped wheels (the default install) were never affected. No public-API change.Composite-plot furniture no longer lands on the heatmap:
feature_map()andheatmap()place their colorbar and legends below the grid in figure coordinates. Ending a cell with the usualplt.tight_layout(); plt.show()re-packed the axes and pulled that furniture back onto the heatmap. Both methods now manage their own layout and neutralizetight_layouton the returned figure, so the composed layout survives the standard idiom (fig.savefig(..., bbox_inches="tight")andplt.show()are unaffected).Consistent feature-map / heatmap layout at any figure size: several dense-grid / fixed-
figsizelayout fixes forfeature_map()andheatmap(). The no-sequence TMD/JMD bar is a constant height (a fixed fraction of a grid cell-row) rather than scaling with the figure. Underauto_fontthe subcategory row labels and the cumulative-importance%annotations shrink independently until they no longer overlap (re-run on the final layout, below the former 5pt floor if a tight fixedfigsizeneeds it). The■feature-impact markers scale with the cell size so they never overflow a small cell. On a manualfigsizethe three legends are laid out as one aligned bottom row (the grid cells adapting to the reserved space, the figure keeping its exact size), and on a very narrow figure the colorbar drops to its own row below the category legend instead of colliding with it. The standalone heatmap now uses the same cell height as the feature map.Sequence bar in CPP-SHAP plots: with
seq_char_fill=True(the auto_font default),feature_map(),heatmap(), andprofile()drew each residue’s colored background as a glyph-sized text box, so narrow letters left hairline white gaps and the TMD/JMD band read as ragged against the heatmap grid. Each residue now gets a seamless full-width (one-column) colored cell, centered on its column, so the sequence band is gap-free and aligned.seq_char_fill=Falsekeeps the legacy glyph-box rendering unchanged.BH-adjusted p-values (#343):
p_val_fdr_bhindf_featnow follows canonical Benjamini–Hochberg — the reverse cumulative-minimum (monotonicity) step was missing, so the reported values could be non-monotone / slightly conservative in non-monotone regions. Only the reported column changes; feature selection and ranking (abs_auc/abs_mean_dif) are unaffected.run()withn_jobs > 1no longer crashes in non-interactive contexts (e.g.python -c, heredocs, some subprocess shells) where starting amultiprocessing.Managerfor the cross-process progress bar raisedEOFError/OSError. The Manager is now created best-effort: on failure CPP degrades to the thread-safe, single-process progress path and the run completes normally instead of aborting (previously the only workaround wasn_jobs=1). When the Manager is available, behavior and output are unchanged.CPP splits on free peptides / short parts (#338):
ap.find_featuresand thePattern/PeriodicPatternsplits were unusable on free peptides with no flanking context (the linear-epitope case).find_features(search="fast")and its Stage-3 simplify step ignored the requested / winning split configuration and always used the default (len_max=15,n_split_max=15), so any target region shorter than ~15 residues raised. Now:CPP auto-caps splits to the shortest part instead of raising. When a
df_partssequence part is too short for the requestedsplit_kws,CPPcaps theSegmentn_split_maxand drops thePattern/PeriodicPatternsplit types that cannot fit (Segmentis always kept), emits oneUserWarning, and stores the cappedsplit_kwsasself.split_kws(used by bothrun()andrun_num()). For parts long enough for the requested splits this is a no-op, so results for flanked inputs are byte-identical.``find_features`` handles free peptides end to end. The bounded
kwsdict now acceptslen_max(and actually honorsn_split_max). Passingkws={"n_jmd": 0}(no flanking context) switches the part sweep to TMD-only (the whole peptide is one part, instead of half-TMD composite fragments) and caps the swept ``n_split_max`` range to the shortest part length, deduped, with aUserWarning. The stagedbalanced/exhaustivesearches no longer hard-error on short parts. On normal (long-part) inputs the range cap is a no-op.
Deprecated
``AAlogo`` / ``AAlogoPlot`` are deprecated in favour of the PascalCase
AALogo/AALogoPlot. The old names remain importable from bothaaanalysisandaaanalysis.seq_analysisand now emit aDeprecationWarningon attribute access; they are scheduled for removal in the next major release. Existing code keeps working unchanged, so the import can be updated at your convenience.The strict-semver deprecation policy and the
deprecateddecorator are now in force for all further public-API renames and removals.
Version 1.0 (Stable Version)
v1.0.3 (2026-04-28)
Added
AALogo: New class for amino acid logo visualization.AALogoPlot: New plotting class for AALogo visualizations.
Changed
Python Support: Dropped Python 3.9 (end-of-life) and added Python 3.13 and 3.14 support. Supported versions are now 3.10, 3.11, 3.12, 3.13, and 3.14.
Dependency Management: Migrated from
requirements.txtfiles to a singlepyproject.tomlas the source of truth for all dependencies. Introduced structured dependency extras:aaanalysis[pro],aaanalysis[docs], andaaanalysis[dev].Package Manager: Added full
uvsupport alongside existingpipandPoetrycompatibility.CI/CD: Updated all GitHub Actions workflows to reflect new Python version matrix and consolidated dependency installation via extras.
Other
Documentation: Updated
ReadTheDocsconfiguration to install dependencies directly frompyproject.tomlviaaaanalysis[docs]extra.Cleanup: Removed legacy
requirements.txt,docs/requirements_dev.txt, anddocs/requirements_wo_pro.txtfiles.
v1.0.2 (2025-06-17)
Improved
Faster CPP Pipeline: Major performance boost in
CPP.run()through optimized generation and filtering of part-split-scale combinations. Depending on the number of scales, runtime is now 3–5× faster on standard hardware.Feature Map Enhancement:
CPP.feature_map()now includes a top bar plot showing cumulative feature importance per residue, improving interpretability. This visualization is also included in the CPP profile output.
Fixed
fetch_alphafold(): Resolve download URLs through the AlphaFold API instead of a hardcoded file version. AlphaFold DB renamed its filesv4→v6, which had silently broken every fetch (all entries returnedalphafold_ok=False); the fetch now tracks the current version automatically. Added anetwork-marked live test (tests/integration/) so an upstream API/version change is caught instead of slipping past the mocked unit tests.General Bug Fixes: Minor fixes related to dependency resolution and edge-case behavior.
Documentation: Removed inconsistencies in documentation for selected functions and plotting options.
Other
Branding: Introduced updated logo and favicon (legacy version preserved under docs/source/_artwork/logos/legacy/).
Landing Page Visual: Added a main conceptual sketch to the documentation landing page illustrating the core CPP idea — comparing two sequence sets to derive their critical difference, the physicochemical signature.
v1.0.1 (2025-01-29)
Improved
Pro Feature Accessibility: Improved integration of aaanalysis[pro] features in IDEs. Clicking on a pro feature now directs users to its exact class implementation instead of the main
__init__.pyfile.Import Error Handling: Improved error handling for missing dependencies in the aaanalysis[pro] version. If dependencies are installed but errors occur during import, users now receive the original import error messages.
Fixed
Feature Map Plot: Resolved a potential mismatch in subcategory ordering between heatmap and bar plot in
aa.cpp_plot().featuremap(). Previously, subcategories with nearly identical names (e.g., “α-helix (C-term)” and “α-helix (C-term, out)”) could appear in an inconsistent order.General Bug Fixes: Minor bug fixes to improve overall stability and functionality.
Other
Dependencies: All dependencies have been updated to ensure compatibility with the latest versions, including full support for
numpy>=2.0.0.
v1.0.0 (2024-07-01)
Added
SequencePreprocessor: A utility data preprocessing class (data handling module).comp_seq_sim(): A function for computing pairwise sequence similarity (data handling module).filter_seq(): A function for redundancy-reduction of sequences (data handling module).options: Juxta Middle Domain (JMD) length can now be globally adjusted using the jmd_n/c_len options.
Changed
ShapModel: The ShapExplainer class has been renamed toShapModelfor consistency with theTreeModelclass and to avoid confusion with the ShapExplainer models from the SHAP package.Dependencies: Biopython is now a required dependency only for the aaanalysis[pro] version.
Module Renaming: The Perturbation module has been renamed to Protein Design module to better reflect its broad functionality.
Fixed
Multiprocessing: Now supported directly at the script level, outside of any functions or classes, in the top-level of the script (global namespace).
Version 0.1 (Beta Version)
v0.1.5 (2024-04-18)
Added
Code of Conduct: Introduced a Code of Conduct to foster a welcoming and inclusive community environment. We encourage all contributors to review the Code of Conduct to understand the expectations and responsibilities when participating in the project.
Changed
License Update: Transitioned the project license from MIT to BSD-3-Clause to better align with our project’s community engagement and protection goals. This change affects how the software can be used and redistributed.
Fixed
Multiprocessing: Replaced native
multiprocessingwith thejoblibmodule forCPPand internal feature matrix creation. This change prevents aRuntimeErrorthat occurred when the main function is not explicitly used.
Other
Dependencies: Update the
seaborndependency to version 0.13.2 or higher to resolve the legend argument error present in versions earlier than 0.13
v0.1.4 (2024-04-09)
Added
Installation Options: Introduced separate installation profiles for the core and professional versions. The core version has reduced dependencies to enhance installation robustness, installable using
pip install aaanalysis. The professional version, designed for advanced usage, includes packages required for our explainable AI module such as SHAP, installable usingpip install aaanalysis[pro].
Changed
API Improvements: General improvement of API for consistency and higher user-friendliness.
Fixed
General Issues: Fix of different check function related API issues.
Other
Python Dependency: Updated the Python version compatibility from <= 3.10 to <= 3.12.
v0.1.3 (2024-02-09)
Added
TreeModel: Wrapper class of tree-based models for Monte Carlo estimates of predictions and feature importance. See TreeModel.ShapExplainer: A wrapper for SHAP (SHapley Additive exPlanations) explainers to obtain Monte Carlo estimates for feature impact. See ShapExplainer.
NumericalFeature: Utility feature engineering class to process and filter numerical data structures. See NumericalFeature.Load_feature: Utility function to load feature sets for protein benchmarking datasets. See load_features.
Changed
API Improvements: General improvement of API for consistency and higher user-friendliness.
Fixed
Interface: Change of internal documentation decorator to hard-coded documentation for better IDE responsiveness.
General Issues: Fix of different check function related API issues.
v0.1.2 (2023-11-06)
Added
CPPPlot: Plotting class for CPP features. See CPPPlot.dPULearnPlot: Plotting class for results of negative identifications by dPULearn. See dPULearnPlot.AAclustPlot: Plotting class for AAclust clustering results. See AAclustPlot.Options: Set system-level settings by a dictionary-like interface (similar to pandas). See options.
Plotting functions: Extension of plotting utility functions.
Changed
API Improvements: General improvement of API.
Fixed
API Improvements: General improvement of API (Application Programming Interface).
Other
Python Dependency: Supports Python versions 3.9 and 3.10.
v0.1.1 (2023-09-11)
Test release of the first beta version.
v0.1.0 (2023-09-11)
First release of the beta version including CPP, dPULearn, and AAclust algorithms as well as the SequenceFeature utility class and data loading functions load_dataset and load_scales.