Skip to content

Commit

Permalink
Merge pull request #72 from moshi4/develop
Browse files Browse the repository at this point in the history
Bump to v1.6.0
  • Loading branch information
moshi4 authored Jun 1, 2024
2 parents bf74abb + 02cbebd commit 3c84789
Show file tree
Hide file tree
Showing 12 changed files with 118 additions and 39 deletions.
23 changes: 19 additions & 4 deletions docs/plot_tips.ipynb

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "pyCirclize"
version = "1.5.0"
version = "1.6.0"
description = "Circular visualization in Python"
authors = ["moshi4"]
license = "MIT"
Expand All @@ -19,7 +19,6 @@ classifiers = [
"Topic :: Scientific/Engineering :: Bio-Informatics",
"Framework :: Matplotlib",
]
include = ["tests"]

[tool.pytest.ini_options]
minversion = "6.0"
Expand Down
2 changes: 1 addition & 1 deletion src/pycirclize/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from pycirclize.circos import Circos

__version__ = "1.5.0"
__version__ = "1.6.0"

__all__ = [
"Circos",
Expand Down
45 changes: 34 additions & 11 deletions src/pycirclize/circos.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@
class Circos:
"""Circos Visualization Class"""

# By default, after saving a figure using the `savefig()` method, figure object is
# automatically deleted to avoid memory leaks (no display on jupyter notebook)
# If you want to display the figure on jupyter notebook using `savefig()` method,
# set clear_savefig=False.
clear_savefig: bool = True

def __init__(
self,
sectors: Mapping[str, int | float | tuple[float, float]],
Expand Down Expand Up @@ -522,8 +528,10 @@ def initialize_from_tree(
Returns
-------
circos, tv : tuple[Circos, TreeViz]
Circos & TreeViz instances initialized from tree
circos : Circos
Circos instance
tv : TreeViz
TreeViz instance
"""
# Initialize circos sector with tree size
tree = TreeViz.load_tree(tree_data, format=format)
Expand Down Expand Up @@ -946,7 +954,9 @@ def colorbar(
vmax: float = 1,
cmap: str | Colormap = "bwr",
orientation: str = "vertical",
label: str | None = None,
colorbar_kws: dict[str, Any] | None = None,
label_kws: dict[str, Any] | None = None,
tick_kws: dict[str, Any] | None = None,
) -> None:
"""Plot colorbar
Expand All @@ -964,27 +974,35 @@ def colorbar(
<https://matplotlib.org/stable/tutorials/colors/colormaps.html>
orientation : str, optional
Colorbar orientation (`vertical`|`horizontal`)
label : str | None, optional
Colorbar label. If None, no label shown.
colorbar_kws : dict[str, Any] | None, optional
Colorbar properties (e.g. `dict(label="name", format="%.1f", ...)`)
Colorbar properties (e.g. `dict(format="%.1f", ...)`)
<https://matplotlib.org/stable/api/colorbar_api.html>
label_kws : dict[str, Any] | None, optional
Text properties (e.g. `dict(size=15, color="red", ...)`)
<https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.text.html>
tick_kws : dict[str, Any] | None, optional
Axes.tick_params properties (e.g. `dict(labelsize=12, colors="red", ...)`)
<https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.tick_params.html>
"""
colorbar_kws = {} if colorbar_kws is None else deepcopy(colorbar_kws)
label_kws = {} if label_kws is None else deepcopy(label_kws)
tick_kws = {} if tick_kws is None else deepcopy(tick_kws)

def plot_colorbar(ax: PolarAxes) -> None:
axin: Axes = ax.inset_axes(bounds)
norm = Normalize(vmin=vmin, vmax=vmax)
Colorbar(
cb = Colorbar(
axin,
cmap=cmap, # type: ignore
norm=norm,
orientation=orientation, # type: ignore
**colorbar_kws,
)
axin.tick_params(**tick_kws)
if label:
cb.set_label(label, **label_kws)

self._plot_funcs.append(plot_colorbar)

Expand Down Expand Up @@ -1055,9 +1073,6 @@ def savefig(
) -> None:
"""Save figure to file
`circos.savefig("result.png")` is alias for
`circos.plotfig().savefig("result.png")`
Parameters
----------
savefile : str | Path
Expand All @@ -1068,6 +1083,11 @@ def savefig(
Figure size
pad_inches : float, optional
Padding inches
Warnings
--------
To plot a figure that settings a user-defined legend, subtracks, or annotations,
call `fig.savefig()` instead of `gv.savefig()`.
"""
fig = self.plotfig(dpi=dpi, figsize=figsize)
fig.savefig(
Expand All @@ -1077,8 +1097,9 @@ def savefig(
bbox_inches="tight",
)
# Clear & close figure to suppress memory leak
fig.clear()
plt.close(fig)
if self.clear_savefig:
fig.clear()
plt.close(fig)

############################################################
# Private Method
Expand Down Expand Up @@ -1136,8 +1157,10 @@ def _initialize_figure(
Returns
-------
fig, ax : tuple[Figure, PolarAxes]
Figure, PolarAxes
fig : Figure
Figure
ax : PolarAxes
PolarAxes
"""
fig = plt.figure(figsize=figsize, dpi=dpi, tight_layout=True)
ax = fig.add_subplot(projection="polar")
Expand Down
12 changes: 8 additions & 4 deletions src/pycirclize/parser/genbank.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,10 @@ def calc_gc_skew(
Returns
-------
gc_skew_result_tuple : tuple[NDArray[np.int64], NDArray[np.float64]]
Position list & GC skew list
pos_list : NDArray[np.int64]
Position list
gc_skew_list : NDArray[np.float64]
GC skew list
"""
pos_list, gc_skew_list = [], []
seq = self.genome_seq if seq is None else seq
Expand Down Expand Up @@ -200,8 +202,10 @@ def calc_gc_content(
Returns
-------
gc_content_result_tuple : tuple[NDArray[np.int64], NDArray[np.float64]]
Position list & GC content list
pos_list : NDArray[np.int64]
Position list
gc_content_list : NDArray[np.float64]
GC content list
"""
pos_list, gc_content_list = [], []
seq = self.genome_seq if seq is None else seq
Expand Down
16 changes: 12 additions & 4 deletions src/pycirclize/parser/gff.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,12 @@ def _parse_gff(
Returns
-------
gff_records, start, end : tuple[list[GffRecord], int, int]
GFF record list, start, end
gff_records : list[GffRecord]
GFF record list
start : int
Start position of target_seqid record
end : int
End position of target_seqid record
"""
gff_file = Path(gff_file)
if gff_file.suffix == ".gz":
Expand Down Expand Up @@ -308,8 +312,12 @@ def _parse_gff_textio(
Returns
-------
gff_records, start, end : tuple[list[GffRecord], int, int]
GFF record list, start, end
gff_records : list[GffRecord]
GFF record list
start : int
Start position of target_seqid record
end : int
End position of target_seqid record
"""
# Parse GFF lines
gff_all_lines = handle.read().splitlines()
Expand Down
15 changes: 9 additions & 6 deletions src/pycirclize/parser/matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,16 +202,19 @@ def to_links(
) -> list[tuple[tuple[str, float, float], tuple[str, float, float]]]:
"""Convert matrix to links data for `circos.link()` method
>>> # Example usage
Returns
-------
link_target1 : tuple[str, float, float]
name1, start1, end1
link_target2 : tuple[str, float, float]
name2, start2, end2
Examples
--------
>>> matrix = Matrix(matrix_file)
>>> circos = Circos(matrix.to_sectors())
>>> for link in matrix.to_links():
>>> circos.link(*link)
Returns
-------
links : list[tuple[tuple[str, float, float], tuple[str, float, float]]]
List of link `((name1, start1, end1), (name2, end2, start2))`
"""
return self._links

Expand Down
6 changes: 4 additions & 2 deletions src/pycirclize/track.py
Original file line number Diff line number Diff line change
Expand Up @@ -1318,8 +1318,10 @@ def _to_arc_radr(
Returns
-------
arc_rad, arc_r : tuple[list[float], list[float]]
Arc radian list, Ard radius list
arc_rad : list[float]
Arc radian list
arc_r : list[float]
Arc radius list
"""
all_arc_rad, all_arc_r = [], []
for i in range(len(rad) - 1):
Expand Down
6 changes: 4 additions & 2 deletions src/pycirclize/tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,8 +442,10 @@ def _set_uniq_innode_name(self, tree: Tree) -> tuple[Tree, list[str]]:
Returns
-------
tree, uniq_node_names: tuple[Tree, list[str]]
Unique node name set tree object & set unique node names
tree : Tree
Tree (set unique node names)
uniq_node_names : list[str]
Unique node names
"""
tree = deepcopy(tree)
uniq_innode_names: list[str] = []
Expand Down
3 changes: 2 additions & 1 deletion src/pycirclize/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
load_example_tree_file,
load_prokaryote_example_file,
)
from pycirclize.utils.helper import ColorCycler, calc_group_spaces
from pycirclize.utils.helper import ColorCycler, calc_group_spaces, is_pseudo_feature

__all__ = [
"plot",
Expand All @@ -17,4 +17,5 @@
"load_example_tree_file",
"ColorCycler",
"calc_group_spaces",
"is_pseudo_feature",
]
8 changes: 6 additions & 2 deletions src/pycirclize/utils/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,12 @@ def load_eukaryote_example_dataset(
Returns
-------
chr_bed_file, cytoband_file, chr_links : tuple[Path, Path, list[ChrLink]]
BED file, Cytoband file, Chromosome links
chr_bed_file : Path
BED file
cytoband_file : Path
Cytoband file
chr_links : list[ChrLink]
Chromosome links
"""
# Check specified name dataset exists or not
if name not in config.EUKARYOTE_DATASET:
Expand Down
18 changes: 18 additions & 0 deletions src/pycirclize/utils/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import matplotlib as mpl
import numpy as np
from Bio.SeqFeature import SeqFeature
from matplotlib.colors import Colormap, to_hex


Expand Down Expand Up @@ -129,3 +130,20 @@ def calc_group_spaces(
return spaces
else:
return spaces[:-1]


def is_pseudo_feature(feature: SeqFeature) -> bool:
"""Check target feature is pseudo or not from qualifiers tag
Parameters
----------
feature : SeqFeature
Target feature
Returns
-------
check_result : bool
pseudo check result
"""
quals = feature.qualifiers
return True if "pseudo" in quals or "pseudogene" in quals else False

0 comments on commit 3c84789

Please sign in to comment.