{"id":37084386,"url":"https://github.com/peleiden/pelutils","last_synced_at":"2026-01-14T10:19:37.805Z","repository":{"id":38398538,"uuid":"297631005","full_name":"peleiden/pelutils","owner":"peleiden","description":"Utility module for Python","archived":false,"fork":false,"pushed_at":"2025-07-05T13:57:39.000Z","size":441,"stargazers_count":6,"open_issues_count":14,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-07-05T15:02:38.968Z","etag":null,"topics":["data-science","logging","machine-learning","parsing","profiling"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/peleiden.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-09-22T11:44:01.000Z","updated_at":"2025-02-23T11:15:17.000Z","dependencies_parsed_at":"2024-02-04T19:23:28.369Z","dependency_job_id":"8217c8ae-93c9-4aef-9078-2b457759cdfb","html_url":"https://github.com/peleiden/pelutils","commit_stats":{"total_commits":237,"total_committers":6,"mean_commits":39.5,"dds":"0.11814345991561181","last_synced_commit":"579b276d8540f9f8018593f01fbc06f68f7838e4"},"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"purl":"pkg:github/peleiden/pelutils","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peleiden%2Fpelutils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peleiden%2Fpelutils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peleiden%2Fpelutils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peleiden%2Fpelutils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/peleiden","download_url":"https://codeload.github.com/peleiden/pelutils/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peleiden%2Fpelutils/sbom","scorecard":{"id":726753,"data":{"date":"2025-08-18","repo":{"name":"github.com/peleiden/pelutils","commit":"d2bf581bb873be7efa4c5f6e19a73b1805f72779"},"scorecard":{"version":"v5.2.1-41-g40576783","commit":"40576783fda6698350fcbbeaea760ff827433034"},"score":4.4,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/14 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#code-review"}},{"name":"Maintained","score":7,"reason":"9 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 7","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/dist.yml:1","Warn: no topLevel permission defined: .github/workflows/pytest.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/dist.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/peleiden/pelutils/dist.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/dist.yml:20: update your workflow using https://app.stepsecurity.io/secureworkflow/peleiden/pelutils/dist.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/dist.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/peleiden/pelutils/dist.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/dist.yml:47: update your workflow using https://app.stepsecurity.io/secureworkflow/peleiden/pelutils/dist.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/dist.yml:56: update your workflow using https://app.stepsecurity.io/secureworkflow/peleiden/pelutils/dist.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/dist.yml:63: update your workflow using https://app.stepsecurity.io/secureworkflow/peleiden/pelutils/dist.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/dist.yml:73: update your workflow using https://app.stepsecurity.io/secureworkflow/peleiden/pelutils/dist.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/dist.yml:78: update your workflow using https://app.stepsecurity.io/secureworkflow/peleiden/pelutils/dist.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pytest.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/peleiden/pelutils/pytest.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pytest.yml:29: update your workflow using https://app.stepsecurity.io/secureworkflow/peleiden/pelutils/pytest.yml/master?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/dist.yml:30","Warn: pipCommand not pinned by hash: .github/workflows/pytest.yml:35","Warn: pipCommand not pinned by hash: .github/workflows/pytest.yml:36","Warn: pipCommand not pinned by hash: .github/workflows/pytest.yml:37","Info:   0 out of   8 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   2 third-party GitHubAction dependencies pinned","Info:   0 out of   4 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#vulnerabilities"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#security-policy"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#signed-releases"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.txt:0","Info: FSF or OSI recognized license: MIT License: LICENSE.txt:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#branch-protection"}},{"name":"Packaging","score":10,"reason":"packaging workflow detected","details":["Info: Project packages its releases by way of GitHub Actions.: .github/workflows/dist.yml:67"],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#packaging"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 20 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-22T13:02:51.454Z","repository_id":38398538,"created_at":"2025-08-22T13:02:51.455Z","updated_at":"2025-08-22T13:02:51.455Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28416908,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T10:18:03.274Z","status":"ssl_error","status_checked_at":"2026-01-14T10:16:11.865Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["data-science","logging","machine-learning","parsing","profiling"],"created_at":"2026-01-14T10:19:36.957Z","updated_at":"2026-01-14T10:19:37.787Z","avatar_url":"https://github.com/peleiden.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pelutils\n\n[![pytest](https://github.com/peleiden/pelutils/actions/workflows/pytest.yml/badge.svg?branch=master)](https://github.com/peleiden/pelutils/actions/workflows/pytest.yml)\n[![Coverage Status](https://coveralls.io/repos/github/peleiden/pelutils/badge.svg?branch=master)](https://coveralls.io/github/peleiden/pelutils?branch=master)\n\nThe Swiss army knife of Python projects.\n\n- A simple and powerful logger with colourful printing, stacktraces, and log file rotation.\n- Parsing for combining config files and command-line arguments - especially useful developing algorithms with many parameters.\n- A timer inspired by Matlab's `tic` and `toc`.\n- Simple, near-zero cost performance profiler.\n- An extension to the built-in `dataclass` for saving and loading data.\n- Table formatting with built-in LaTeX support.\n- Miscellaneous standalone functions - see `pelutils/__init__.py`.\n- Data-science submodule with extra utilities for statistics, plotting with `matplotlib`, and machine learning using `PyTorch`.\n- `unique` function in the style of `numpy.unique` which runs in linear time, making it significantly.\n\n`pelutils` supports Python 3.9+.\n\nTo install, simply run `pip install pelutils`.\nA small subset of the functionality requires `PyTorch`, which has to be installed separately.\n\nThere are a few examples for some parts of the library, namely plotting, in the `examples`.\nThese require `click` to be installed as well as the library itself.\nHowever, most of the documentation and examples are listed here in this readme.\n\n## Timing and Code Profiling\n\nSimple time taker inspired by Matlab Tic, Toc, which also has profiling tooling.\n\n```py\nfrom pelutils import TT, TickTock\n\n# Time a task\nTT.tick()\n\u003csome task\u003e\nseconds_used = TT.tock()\n\n# Profile a for loop\nfor i in range(100):\n    TT.profile(\"Repeated code\")\n    \u003csome task\u003e\n    TT.profile(\"Subtask\")\n    \u003csome subtask\u003e\n    TT.end_profile()\n    TT.end_profile()\nprint(TT)  # Prints a table view of profiled code sections\n\n# Alternative syntax using with statement\nwith TT.profile(\"The best task\"):\n    \u003csome task\u003e\n\n# When using multiprocessing, it can be useful to simulate multiple hits of the same profile\nwith mp.Pool() as p, TT.profile(\"Processing 100 items on multiple threads\", hits=100):\n    p.map(100 items)\n# Similar for very quick loops\na = 0\nwith TT.profile(\"Adding 1 to a\", hits=100):\n    for _ in range(100):\n        a += 1\n\n# Examples so far use a global TickTock instance, which is convenient,\n# but it can also be desirable to use for multiple different timers, e.g.\ntt1 = TickTock()\ntt2 = TickTock()\nt1_interval = 1  # Do task 1 every second\nt2_interval = 2  # Do task 2 every other second\ntt1.tick()\ntt2.tick()\nwhile True:\n    if tt1.tock() \u003e t1_interval:\n        \u003ctask 1\u003e\n        tt1.tick()\n    if tt2.tock() \u003e t2_interval:\n        \u003ctask 2\u003e\n        tt2.tick()\n    time.sleep(0.01)\n```\n\n## Data Storage\n\nThe DataStorage class is an augmentation of the dataclass that incluces save and load functionality.\nThis simplifies saving data, as only save command has to be issued for all data, and it keeps type\nhinting when loading data compared to e.g. a dictionary.\n\nData is in general preserved exactly as-is when saved data is loaded into memory with few exceptions.\nNotably, tuples are considered json-serializble, and so will be saved to the json file and will be\nloaded as lists.\n\nUsage example:\n\n```py\n@dataclass\nclass ResultData(DataStorage):\n    shots: int\n    goalscorers: list\n    dists: np.ndarray\n\nrdata = ResultData(shots=1, goalscorers=[\"Max Fenger\"], dists=np.ones(22)*10)\nrdata.save(\"max\")\n# Now shots and goalscorers are saved in \u003cpwd\u003e/max/ResultData.json and dists in \u003cpwd\u003e/max/ResultData.pkl\n\n# Then to load\nrdata = ResultData.load(\"max\")\nprint(rdata.goalscorers)  # [\"Max Fenger\"]\n```\n\n## Config and Command-line Argument Parsing\n\nPython has built-in support for both config files (the `ArgumentParser` and `ConfigParser`, respectively), but nothing for parsing both.\nThe Pelutils `Parser` supports both, while also allowing for much stricter checking of types and presence of arguments.\nIt is useful for any application relying on config files where one may want to overwrite certain arguments from the command-line.\nIt's prime usecase, though, is for development of parametric algorithms, such as machine learning engineering.\n\nConsider the execution of a file `main.py` with the command line call\n```\npython main.py path/to/output -c path/to/config/file.ini --data-path path/to/data\n```\nThe config file could contain\n```ini\n[DEFAULT]\nlearning-rate=1e-4\nfp16\n\n[LOWLR]\nlearning-rate=1e-5\n\n[NOFP16]\nfp16=False\n```\nwhere `main.py` contains\n```py\noptions = [\n    # Mandatory argument with set abbreviation -p\n    Argument(\"data-path\", help=\"Path to where data is located\", abbrv\"-p\"),\n    # Optional argument with auto-generated abbreviation -l\n    Option(\"learning-rate\", default=1e-5, help=\"Learning rate to use for gradient descent steps\"),\n    # Boolean flag with auto-generated abbreviation -f\n    Flag(\"fp16\", help=\"Use mixed precision for training\"),\n]\nparser = Parser(*options, multiple_jobs=True)  # Two jobs are specified in the config file, so multiple_jobs=True\nlocation = parser.location  # Experiments are stored here. In this case path/to/output\njob_descriptions = parser.parse_args()\n# Run each experiment\nfor job in job_descriptions:\n    # Get the job as a dictionary\n    job_dict = job.todict()\n    # Clear directory where job is located and put a documentation file there\n    job.prepare_directory()\n    # Get location of this job as job.location\n    run_experiment(job)\n```\n\nThis could then by run by\n`python main.py data/my-big-experiment --learning-rate 1e-5`\nor by\n`python main.py data/my-big-experiment --config cfg.ini`\nor using a combination where CLI args takes precedence:\n`python main.py data/my-big-experiment --config cfg.ini --learning-rate 1e-5`\nwhere `cfg.ini` could contain\n\n# Logging\n\nThe logging submodule contains a simple yet feature-rich logger which fits common needs. Can be imported from `pelutils` directly, e.g. `from pelutils import log`.\n\n```py\nfrom pelutils import log, Logger\n\n# Configure logger for the script\nlog.configure(\"path/to/save/log.log\")\n\n# Start logging\nfor i in range(70):  # Nice\n    log(\"Execution %i\" % i)\n\n# Sections\nlog.section(\"New section in the logfile\")\n\n# Adjust logging levels\nlog.warning(\"Will be logged\")\nwith log.level(LogLevels.ERROR):  # Only log at ERROR level or above\n    log.warning(\"Will not be logged\")\nwith log.no_log:\n    log.section(\"I will not be logged\")\n\n# Rotation\n# Start a new log file every hour (or day, month, or year)\nlog.configure(\"path/to/save/log.log\", rotation=\"hour\")\n# Start a new log file when the current one reaches a certain size\nlog.configure(\"path/to/save/log.log\", rotation=\"5 MB\")\n\n# Error handling\n# The zero-division error and stacktrace is logged\nwith log.log_errors:\n    0 / 0\n# Entire chained stacktrace is logged\nwith log.log_errors:\n    try:\n        0 / 0\n    except ZeroDivisionError as e:\n        raise ValueError(\"Denominator must be non-zero\") from e\n\n# User input - acts like built-in input but logs both prompt and user input\ninp = log.input(\"Continue [Y/n]? \")\n# Parse yes/no user input\ncont = log.parse_bool_input(inp, default=True)\n\n# Log all logs from a function at the same time\n# This is especially useful when using multiple threads so logging does not get mixed up\ndef fun():\n    with log.collect:\n        log(\"Hello there\")\n        log(\"General Kenobi!\")\nwith mp.Pool() as p:\n    p.map(fun, args)\n\n# It is also possible to create multiple loggers by importing the Logger class, e.g.\nlog2 = Logger()\nlog2.configure(\"path/to/save/log2.log\")\n```\n\n# Data Science\n\nThis submodule contains various utility functions for data science, statistics, plotting, and machine learning.\n\n## Statistics\n\nIncludes various commonly used statistical functions.\nThere are also wrappers around a number of scipy distributions reparametrized as in Jim Pitman's \"Probability\", instead of using scale and loc, which can be quite unintuitive for many distributions.\n\n```py\nfrom pelutils.ds.stats import z, corr_zi\nfrom pelutils.ds.distributions import expon\n\n# Get one sided z value for exponential(lambda=2) distribution with a significance level of 1 %\nzval = z(alpha=0.01, two_sided=False, distribution=expon(2))\n\n# Get correlation, confidence interval, and p value for two vectors\na, b = np.random.randn(100), np.random.randn(100)\nr, lower_r, upper_r, p = corr_ci(a, b, alpha=0.01)\n```\n\n## Plotting\n\n`pelutils` provides plotting utilities based on `matplotlib`.\nMost notable is the `Figure` context class, which attempts to remedy some of the common grievances with `matplotlib`,\ne.g. having to remember the correct `kwargs` and `rcParams` for setting font sizes, legend edge colour etc.\n```py\nfrom pelutils.ds.plots import Figure\n\n# The following makes a plot and saves it to `plot.png`.\n# The seaborn is style is used for demonstration, but if the `style` argument\n# is not given, the default matplotlib style is used.\n# The figure and font size are also given for demonstration, but their default\n# values are increased compared to matplotlib's default, as these are generally\n# too small for finished plots.\nwith Figure(\"plot.png\", figsize=(20, 10), style=\"seaborn\", fontsize=20):\n    plt.scatter(x, y, label=\"Data\")\n    plt.grid()\n    plt.title(\"Very nice plot\")\n# The figure is automatically saved to `plot.png` and closed, such that\n# plt.plot can be used again from here.\n# Figure changes `matplotlib.rcParams`, but these changes are also undone\n# after the end of the `with statement`.\n```\n\nThe plotting utilies also include binning functions for creating nice histograms.\nThe `histogram` function produces bins based on a binning function, of which three are provided:\n\n- `linear_binning`: Bins are spaced evenly from the lowest to the largest value of the data.\n- `log_binning`: Bins are log-spaced from the lowest to the largest value of the data, which is assumed to be positive.\n- `normal_binning`: Bins are distributed according to the distribution of the data, such there are more bins closer to the center of the data. This is useful if the data somewhat resembles a normal distribution, as the resolution will be the greatest where there is the most data.\n\nIt is also possible to provide custom binning functions.\n\n`histogram` provide both `x` and `y` coordinates, making it simple to use with argument unpacking:\n```py\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom pelutils.ds.plots import histogram, normal_binning\n\n# Generate normally distributed data\nx = np.random.randn(100)\n# Plot distribution\nplt.plot(*histogram(x, binning_fn=normal_binning))\n```\n\nFinally, different smoothing functions are provided.\nThe two most common are `moving_avg` and `exponential_avg` which smooth the data using a moving average and exponential smoothing, respectively.\n\nThe `double_moving_avg` is special in that the number of smoothed data points do not depend on the number of given data points but is instead based on a given number of samples, which allows the resulting smoothed curve to not by jagged as happens with the other smoothing functions.\nIt also has two smoothness parameters, which allows a large degree of smoothness control.\n\nApart from smoothness parameters, all smoothness functions have the same call signature:\n```py\nfrom pelutils.ds.plots import double_moving_avg\n\n# Generate noisy data\nn = 100\nx = np.linspace(-1, 1, n)\ny = np.random.randn(n)\n\n# Plot data along with smoothed curve\nplt.plot(*double_moving_avg(x, y))\n# If x is not given, it is assumed to go from 0 to n-1 in steps of 1\nplt.plot(*double_moving_avg(y))\n```\n\nExamples of all the plotting utilities are shown in the `examples` directory.\n\n# Supported platforms\n\nPrecompiled wheels are provided for most common platforms.\nNotably, they are not provided for 32-bit systems.\nIf no wheel is provided, `pip` should attempt a source install.\nIf all else fails, it is possible to install from source by pointing `pip` to Github directly:\n```\npip install git+https://github.com/peleiden/pelutils.git@release#egg=pelutils\n```\nIt is also possible to install from source using `pip`'s `--no-binary` option.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeleiden%2Fpelutils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpeleiden%2Fpelutils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeleiden%2Fpelutils/lists"}