Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

some modernization #75

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
repos:
- repo: https://github.com/PyCQA/isort
rev: 5.9.3
rev: 5.10.1
hooks:
- id: isort

- repo: https://github.com/psf/black
rev: 21.9b0
rev: 21.12b0
hooks:
- id: black
language_version: python3
Expand Down
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
# termplotlib
<p align="center">
<a href="https://github.com/nschloe/termplotlib"><img alt="termplotlib" src="https://nschloe.github.io/termplotlib/termplotlib-logo.svg" width="60%"></a>
<p align="center">Plotting on the command line.</p>
</p>

[![PyPi Version](https://img.shields.io/pypi/v/termplotlib.svg?style=flat-square)](https://pypi.org/project/termplotlib)
[![PyPI pyversions](https://img.shields.io/pypi/pyversions/termplotlib.svg?style=flat-square)](https://pypi.org/pypi/termplotlib/)
[![GitHub stars](https://img.shields.io/github/stars/nschloe/termplotlib.svg?style=flat-square&logo=github&label=Stars&logoColor=white)](https://github.com/nschloe/termplotlib)
[![PyPi downloads](https://img.shields.io/pypi/dm/termplotlib.svg?style=flat-square)](https://pypistats.org/packages/termplotlib)
[![Downloads](https://pepy.tech/badge/termplotlib/month?style=flat-square)](https://pepy.tech/project/termplotlib)

<!--[![PyPi downloads](https://img.shields.io/pypi/dm/termplotlib.svg?style=flat-square)](https://pypistats.org/packages/termplotlib)-->

[![gh-actions](https://img.shields.io/github/workflow/status/nschloe/termplotlib/ci?style=flat-square)](https://github.com/nschloe/termplotlib/actions?query=workflow%3Aci)
[![codecov](https://img.shields.io/codecov/c/github/nschloe/termplotlib.svg?style=flat-square)](https://codecov.io/gh/nschloe/termplotlib)
Expand Down
8 changes: 5 additions & 3 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = termplotlib
version = 0.3.9
version = 0.3.10
author = Nico Schlömer
author_email = [email protected]
description = Python plotting for the command line
Expand Down Expand Up @@ -37,9 +37,11 @@ keywords =
package_dir =
=src
packages = find:
install_requires =
numpy >= 1.20
python_requires = >=3.7

[options.packages.find]
where=src

[options.extras_require]
all =
numpy >= 1.20
38 changes: 16 additions & 22 deletions src/termplotlib/barh.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
import decimal
from typing import List, Optional
from __future__ import annotations

import numpy as np
from numpy.typing import ArrayLike
import decimal
import numbers

from .helpers import is_unicode_standard_output


def barh(
vals: List[int],
labels: Optional[List[str]] = None,
vals: list[int],
labels: list[str] | None = None,
max_width: int = 40,
bar_width: int = 1,
show_vals: bool = True,
val_format: Optional[str] = None,
val_format: str | None = None,
force_ascii: bool = False,
):
partition = _get_partition(vals, max_width)
partition = np.repeat(partition, bar_width, axis=1)

if is_unicode_standard_output() and not force_ascii:
chars = [" ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█"]
Expand All @@ -33,16 +30,16 @@ def barh(
if show_vals:
if val_format is not None:
cfmt = val_format
elif np.issubdtype(np.asarray(vals).dtype, float):
elif all(isinstance(val, numbers.Integral) for val in vals):
max_len = max(len(str(val)) for val in vals)
cfmt = f"{{:{max_len}d}}"
elif all(isinstance(val, numbers.Real) for val in vals):
# find max decimal length
# https://stackoverflow.com/a/6190291/353337
num_digits = max(
-decimal.Decimal(str(val)).as_tuple().exponent for val in vals
)
cfmt = f"{{:.{num_digits}f}}"
elif np.issubdtype(np.asarray(vals).dtype, np.integer):
max_len = max(len(str(val)) for val in vals)
cfmt = f"{{:{max_len}d}}"
else:
cfmt = "{}"
fmt.append("[" + cfmt + "]")
Expand All @@ -51,9 +48,7 @@ def barh(
fmt = " ".join(fmt)

out = []
for k, (val, num_full, remainder) in enumerate(
zip(vals, partition[0], partition[1])
):
for k, (val, num_full, remainder) in enumerate(zip(vals, *partition)):
data = []
if labels is not None:
data.append(str(labels[k]))
Expand All @@ -67,12 +62,11 @@ def barh(
return out


def _get_partition(values: ArrayLike, max_size: int):
values = np.asarray(values)
assert np.all(values >= 0)
maxval = np.max(values)
def _get_partition(values: list[int], max_size: int) -> tuple[list[int], list[int]]:
assert all(val >= 0 for val in values)
maxval = max(values)
if maxval == 0:
maxval = 1

eighths = np.around(values / maxval * max_size * 8).astype(int)
return np.array([eighths // 8, eighths % 8])
eighths = [round(val / maxval * max_size * 8) for val in values]
return [val // 8 for val in eighths], [val % 8 for val in eighths]
6 changes: 3 additions & 3 deletions src/termplotlib/figure.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Optional
from __future__ import annotations

from .barh import barh
from .helpers import create_padding_tuple
Expand All @@ -11,13 +11,13 @@ def figure(*args, **kwargs):


class Figure:
def __init__(self, width: Optional[int] = None, padding: int = 0):
def __init__(self, width: int | None = None, padding: int = 0):
self._content = []
self._width = width
self._subfigures = None
self._padding = create_padding_tuple(padding)

def __rich_console__(self, *args):
def __rich_console__(self, *_):
yield self.get_string()

def aprint(self, string):
Expand Down
5 changes: 3 additions & 2 deletions src/termplotlib/helpers.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from __future__ import annotations

import re
import subprocess
import sys
from typing import List, Tuple, Union


def create_padding_tuple(padding: Union[int, List[int], Tuple[int, int]]):
def create_padding_tuple(padding: int | list[int] | tuple[int, int]):
# self._padding is a 4-tuple: top, right, bottom, left (just like CSS)
if isinstance(padding, int):
out = (padding, padding, padding, padding)
Expand Down
28 changes: 13 additions & 15 deletions src/termplotlib/hist.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
from typing import List, Optional

import numpy as np
from __future__ import annotations

from .barh import _get_partition, barh
from .helpers import is_unicode_standard_output


def hist(
counts: List[int],
bin_edges: List[float],
counts: list[int],
bin_edges: list[float],
orientation: str = "vertical",
max_width: int = 40,
grid=None,
Expand All @@ -30,16 +28,14 @@ def hist(
counts,
bin_edges,
max_width=max_width,
bar_width=bar_width,
force_ascii=force_ascii,
)


def hist_horizontal(
counts: List[int],
bin_edges: List[float],
counts: list[int],
bin_edges: list[float],
max_width: int = 40,
bar_width: int = 1,
show_bin_edges: bool = True,
show_counts: bool = True,
force_ascii: bool = False,
Expand All @@ -56,24 +52,26 @@ def hist_horizontal(
counts,
labels=labels,
max_width=max_width,
bar_width=bar_width,
show_vals=show_counts,
force_ascii=force_ascii,
)


def hist_vertical(
counts: List[int],
counts: list[int],
max_height: int = 10,
bar_width: int = 2,
strip: bool = False,
xgrid: Optional[List[int]] = None,
xgrid: list[int] | None = None,
force_ascii: bool = False,
):
import numpy as np

if xgrid is None:
xgrid = []

partition = _get_partition(counts, max_height)
partition = np.asarray(partition)

if strip:
# Cut off leading and trailing rows of 0
Expand Down Expand Up @@ -112,16 +110,16 @@ def hist_vertical(
return out


def _get_matrix_of_eighths(
nums_full_blocks, remainders, max_size, bar_width: int
) -> np.ndarray:
def _get_matrix_of_eighths(nums_full_blocks, remainders, max_size: int, bar_width: int):
"""
Returns a matrix of integers between 0-8 encoding bar lengths in histogram.

For instance, if one of the sublists is [8, 8, 8, 3, 0, 0, 0, 0, 0, 0], it means
that the first 3 segments should be graphed with full blocks, the 4th block should
be 3/8ths full, and that the rest of the bar should be empty.
"""
import numpy as np

matrix = np.zeros((len(nums_full_blocks), max_size), dtype=int)

for row, num_full_blocks, remainder in zip(matrix, nums_full_blocks, remainders):
Expand Down
23 changes: 12 additions & 11 deletions src/termplotlib/plot.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
from __future__ import annotations

import subprocess
from typing import List, Optional, Tuple


def plot(
x: List[float],
y: List[float],
x: list[float],
y: list[float],
width: int = 80,
height: int = 25,
label: Optional[str] = None,
xlim: Optional[Tuple[float, float]] = None,
ylim: Optional[Tuple[float, float]] = None,
xlabel: Optional[str] = None,
title: Optional[str] = None,
extra_gnuplot_arguments: Optional[List[str]] = None,
label: str | None = None,
xlim: tuple[float, float] | None = None,
ylim: tuple[float, float] | None = None,
xlabel: str | None = None,
title: str | None = None,
extra_gnuplot_arguments: list[str] | None = None,
plot_command: str = "plot '-' w lines",
ticks_scale: int = 0,
):
) -> list[str]:
p = subprocess.Popen(
["gnuplot"],
stdout=subprocess.PIPE,
Expand Down Expand Up @@ -62,5 +63,5 @@ def plot(
return _remove_empty_lines(out.decode())


def _remove_empty_lines(string: str):
def _remove_empty_lines(string: str) -> list[str]:
return string.split("\n")[1:-2]
8 changes: 4 additions & 4 deletions src/termplotlib/subplot.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import List, Optional, Tuple, Union
from __future__ import annotations

from .figure import Figure

Expand All @@ -11,10 +11,10 @@ class SubplotGrid:
def __init__(
self,
layout,
width: Optional[int] = None,
column_widths: Optional[List[int]] = None,
width: int | None = None,
column_widths: list[int] | None = None,
border_style: str = "thin",
padding: Union[int, List[int], Tuple[int, int]] = (1, 2),
padding: int | list[int] | tuple[int, int] = (1, 2),
):
assert (
len(layout) == 2
Expand Down
4 changes: 2 additions & 2 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ isolated_build = True

[testenv]
deps =
numpy
pytest
pytest-cov
pytest-codeblocks
pytest-cov
extras = all
commands =
pytest {posargs} --codeblocks