Git Product home page Git Product logo

uniplot's Introduction

Uniplot

Build Status PyPI Version PyPI Downloads

Lightweight plotting to the terminal. 4x resolution via Unicode.

uniplot demo GIF

When working with production data science code it can be handy to have plotting tool that does not rely on graphics dependencies or works only in a Jupyter notebook.

The use case that this was built for is to have plots as part of your data science / machine learning CI/cd pipeline - that way whenever something goes wrong, you get not only the error and backtrace but also plots that show what the problem was.

Features

  • Unicode drawing, so 4x the resolution (pixels) of usual ASCII plots
  • Super simple API
  • Interactive mode (pass interactive=True)
  • Color mode (pass color=True) useful in particular when plotting multiple series
  • It's fast: Plotting 1M data points takes 100ms thanks to NumPy magic
  • Only one dependency: NumPy (but you have that anyway don't you)

Please note that Unicode drawing will work correctly only when using a font that fully supports the Box-drawing character set. Please refer to this page for a (incomplete) list of supported fonts.

Examples

Note that all the examples are without color and plotting only a single series of data. For using color see the GIF example above.

Plot sine wave

import math
x = [math.sin(i/20)+i/300 for i in range(600)]
from uniplot import plot
plot(x, title="Sine wave")

Result:

                          Sine wave
┌────────────────────────────────────────────────────────────┐
│                                                    ▟▀▚     │
│                                                   ▗▘ ▝▌    │
│                                       ▗▛▜▖        ▞   ▐    │
│                                       ▞  ▜       ▗▌    ▌   │ 2
│                           ▟▀▙        ▗▘  ▝▌      ▐     ▜   │
│                          ▐▘ ▝▖       ▞    ▜      ▌     ▝▌  │
│              ▗▛▜▖        ▛   ▜      ▗▌    ▝▌    ▐▘      ▜  │
│              ▛  ▙       ▗▘   ▝▖     ▐      ▚    ▞       ▝▌ │
│  ▟▀▖        ▐▘  ▝▖      ▟     ▚     ▌      ▝▖  ▗▌        ▜▄│ 1
│ ▐▘ ▐▖       ▛    ▙      ▌     ▐▖   ▗▘       ▚  ▞           │
│ ▛   ▙      ▗▘    ▐▖    ▐       ▙   ▞        ▝▙▟▘           │
│▐▘   ▐▖     ▐      ▌    ▛       ▐▖ ▗▘                       │
│▞     ▌     ▌      ▐   ▗▘        ▜▄▛                        │
│▌─────▐────▐▘───────▙──▞────────────────────────────────────│ 0
│       ▌   ▛        ▝▙▟▘                                    │
│       ▜  ▐▘                                                │
│        ▙▄▛                                                 │
└────────────────────────────────────────────────────────────┘
         100       200       300       400       500       600

Plot global temperature data

Here we are using Pandas to load and prepare global temperature data from the Our World in Data GitHub repository.

First we load the data, rename a column and and filter the data:

import pandas as pd
uri = "https://github.com/owid/owid-datasets/raw/master/datasets/Global%20average%20temperature%20anomaly%20-%20Hadley%20Centre/Global%20average%20temperature%20anomaly%20-%20Hadley%20Centre.csv"
data = pd.read_csv(uri)
data = data.rename(columns={"Global average temperature anomaly (Hadley Centre)": "Global"})
data = data[data.Entity == "median"]

Then we can plot it:

from uniplot import plot
plot(xs=data.Year, ys=data.Global, lines=True, title="Global normalized land-sea temperature anomaly", y_unit=" °C")

Result:

        Global normalized land-sea temperature anomaly
┌────────────────────────────────────────────────────────────┐
│                                                          ▞▀│
│                                                         ▐  │
│                                                         ▐  │
│                                                     ▗   ▌  │ 0.6 °C
│                                           ▙  ▗▄ ▛▄▖▗▘▌ ▞   │
│                                          ▗▜  ▌ ▜  ▚▞ ▚▞    │
│                                          ▐▝▖▐      ▘       │
│                                    ▗   ▗ ▌ ▙▌              │ 0.3 °C
│                                    ▛▖  ▞▙▘  ▘              │
│                              ▖  ▗▄▗▘▐ ▐▘▜                  │
│                            ▟ █  ▞ ▜ ▝▄▘                    │
│   ▗▚   ▗    ▖       ▗   ▖▗▞ █▐  ▌    ▘                     │
│▁▁▁▞▐▁▁▗▘▜▗▀▀▌▁▁▁▁▙▁▁▟▁▁▁▙▐▁▁▜▁▌▞▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁│ 0 °C
│▚ ▐ ▝▖ ▐  ▛  ▌ ▗▄▐ ▌▗▘▌ ▐▝▌    ▝▘                           │
│ ▌▌  ▌ ▞     ▐▗▘ ▛ ▐▞ ▌ ▐                                   │
│ ▝   ▝▖▌     ▐▞    ▝▌ ▚▜▐                                   │
│      ▗▌     ▝        ▝ ▌                                   │
└────────────────────────────────────────────────────────────┘
1,950    1,960    1,970   1,980    1,990    2,000   2,010

Parameters

The plot function accepts a number of parameters, all listed below. Note that only ys is required, all others are optional.

There is also a plot_to_string function with the same signature, if you want the result as a list of strings, to include the output elsewhere.

Data

  • xs - The x coordinates of the points to plot. Can either be None, or a list or NumPy array for plotting a single series, or a list of those for plotting multiple series. Defaults to None, meaning that the x axis will be just the sample index of ys.
  • ys - The y coordinates of the points to plot. Can either be a list or NumPy array for plotting a single series, or a list of those for plotting multiple series.

In both cases, NaN values are ignored.

Note that since v0.12.0 you can also pass a list or an NumPy array of timestamps, and the axis labels should be formatted correctly. Limitations see below.

Options

In alphabetical order:

  • color - Draw series in color. Defaults to False when plotting a single series, and to True when plotting multiple.
  • force_ascii - Force ASCII characters for plotting only. This can be useful for compatibility, for example when using uniplot inside of CI/CD systems that do not support Unicode. Defaults to False.
  • height - The height of the plotting region, in characters. Default is 17.
  • interactive - Enable interactive mode. Defaults to False.
  • legend_labels - Labels for the series. Can be None or a list of strings. Defaults to None.
  • lines - Enable lines between points. Can either be True or False, or a list of those values for plotting multiple series. Defaults to False.
  • line_length_hard_cap - Enforce a hard limit on the number of characters per line of the plot area. This may override the width option if there is not enough space. Defaults to None.
  • title - The title of the plot. Defaults to None.
  • width - The width of the plotting region, in characters. Default is 60. Note that if the line_length_hard_cap option is used and there is not enough space, the actual width may be smaller.
  • x_as_log - Plot the x axis as logarithmic scale. Defaults to False.
  • x_gridlines - A list of x values that have a vertical line for better orientation. Defaults to [0], or to [] if x_as_log is enabled.
  • x_max - Maximum x value of the view. Defaults to a value that shows all data points.
  • x_min - Minimum x value of the view. Defaults to a value that shows all data points.
  • x_unit - Unit of the x axis. This is a string that is appended to the axis labels. Defaults to "".
  • y_as_log - Plot the y axis as logarithmic scale. Defaults to False.
  • y_gridlines - A list of y values that have a horizontal line for better orientation. Defaults to [0], or to [] if y_as_log is enabled.
  • y_max - Maximum y value of the view. Defaults to a value that shows all data points.
  • y_min - Minimum y value of the view. Defaults to a value that shows all data points.
  • y_unit - Unit of the y axis. This is a string that is appended to the axis labels. Defaults to "".

Changing default parameters

uniplot does not store a state of the configuration parameters. However, you can define a new plot funtion with new defaults by defining a partial:

from functools import partial
from uniplot import plot as default_plot
plot = partial(default_plot, height=25, width=80)

This defines a new plot function that is identical to the original, except the default values for width and height are now different.

Experimental features

Plotting histograms

For convenience there is also a histogram function that accepts one or more series and plots bar-chart like histograms. It will automatically discretize the series into a number of bins given by the bins option and display the result.

Additional options, in alphabetical order:

  • bins - Number of bins to use. Defaults to 20.
  • bins_min - Lower limit of the first bin. Defaults to the minimum of the series.
  • bins_max - Upper limit of the last bin. Defaults to the maximum of the series.

When calling the histogram function, the lines option is True by default.

Example:

import numpy as np
x = np.sin(np.linspace(1, 1000))
from uniplot import histogram
histogram(x)

Result:

┌────────────────────────────────────────────────────────────┐
│   ▛▀▀▌                       │                   ▐▀▀▜      │ 5
│   ▌  ▌                       │                   ▐  ▐      │
│   ▌  ▌                       │                   ▐  ▐      │
│   ▌  ▀▀▀▌                    │                ▐▀▀▀  ▝▀▀▜   │
│   ▌     ▌                    │                ▐        ▐   │
│   ▌     ▌                    │                ▐        ▐   │
│   ▌     ▙▄▄▄▄▄▖              │          ▗▄▄▄  ▐        ▐   │
│   ▌           ▌              │          ▐  ▐  ▐        ▐   │
│   ▌           ▌              │          ▐  ▐  ▐        ▐   │
│   ▌           ▌              │          ▐  ▐  ▐        ▐   │
│   ▌           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▜  ▐▀▀▀  ▝▀▀▀        ▐   │
│   ▌                          │    ▐  ▐                 ▐   │
│   ▌                          │    ▐  ▐                 ▐   │
│   ▌                          │    ▐▄▄▟                 ▐   │
│   ▌                          │                         ▐   │
│   ▌                          │                         ▐   │
│▄▄▄▌▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁│▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▐▄▄▄│ 0
└────────────────────────────────────────────────────────────┘
     -1                        0                       1

Plotting time series

There is inital support for using timestamps for the axis labels. It should work with most formats.

Missing so far are nicer axis labels for time stamps, as well as timezone support.

Example:

import numpy as np
dates =  np.arange('2024-02-17T12:10', 4*60, 60, dtype='M8[m]')
from uniplot import plot
plot(xs=dates, ys=[1,2,3,2])

Result:

┌────────────────────────────────────────────────────────────┐
│                                       ▝                    │ 3
│                                                            │
│                                                            │
│                                                            │
│                                                            │
│                                                            │
│                                                            │
│                                                            │
│                    ▘                                      ▝│ 2
│                                                            │
│                                                            │
│                                                            │
│                                                            │
│                                                            │
│                                                            │
│                                                            │
│▖                                                           │ 1
└────────────────────────────────────────────────────────────┘
 12:24:51  12:54:54  13:24:58  13:55:01  14:25:05   14:55:09

Installation

Install via pip using:

pip install uniplot

Contributing

Clone this repository, and install dependecies via poetry install.

You can run the tests via poetry run ./run_tests to make sure your setup is good. Then proceed with issues, PRs etc. the usual way.

uniplot's People

Contributors

h0uter avatar kronosthelate avatar olavolav avatar riga avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

uniplot's Issues

Occasional gaps in lines

Sometimes there are gaps at the end of lines.

To reproduce

>>> from uniplot import plot
>>> plot(xs=[0.433,0.6666], ys=[0.8,0.1133], x_min=0, x_max=1, y_min=0, y_max=1, lines=True)
DEBUG indices_slope -0.8571428571428571 slope -2.939640410958905
DEBUG x_index_start 51
DEBUG x_index_stop 79
DEBUG x_indices_of_line [52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
 76 77 78]
┌────────────────────────────────────────────────────────────┐
││                                                           │ 1.0
││                                                           │ 
││                                                           │ 
││                        ▝▖                                 │ 
││                         ▝▚                                │ 0.7
││                           ▚                               │ 
││                            ▚▖                             │ 
││                             ▝▖                            │ 
││                              ▝▖                           │ 0.5
││                               ▝▚                          │ 
││                                 ▚                         │ 
││                                  ▚▖                       │ 
││                                   ▝▖                      │ 0.3
││                                    ▝▖                     │ 
││                                     ▝▘                    │ 
││                                      ▝                    │ 
││▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁│ 0.0
└────────────────────────────────────────────────────────────┘
 0                                                          1

This is not a bug, but an artifact of the line drawing attempting to be accurate. If the end pixel is drawn because of an end pint that is significantly away from the center of the pixel then this is possible.

Possible solutions

  • The obvious solution would be to draw the line between the middle points of the start and end pixel, not the actual line.
  • An alternative might be to check for gaps and correct it by drawing another pixel.

Use different characters instead of colors

Is is possible to use different characters instead of colors for plotting multiple series?

It would be nice because I use this library for plotting, and then redirect the python script output to a file, which obviously loses the concept of color, so using like "*" and "+" instead of colors you be nice

[Question] Does Uniplot Support .py files?

Hello,

This is an interesting project! Thank you for taking the time to put it together.

Quick question:

When testing out uniplot I'm able to call .plot() from the python console or through ipython, and get a visualization quite easily. However, it does not work when I include uniplot in a .py file and I execute the file.

# foo.py
import unipolot as plot
import math
x = [math.sin(i / 20) + i / 300 for i in range(600)]
p = plot(x)


$ python foo.py
Traceback (most recent call last):
  File "foo.py", line 4, in <module>
    p = plot(x)
TypeError: 'module' object is not callable

Is this expected behaviour, or am I missing something from the docs?

Thanks,

Missing link to repository on PyPI page

I'm not familiar with poetry, but in standard python projects this would be fixed by setting the following in pyproject.toml:

[project.urls]
repository = "https://github.com/olavolav/uniplot"
documentation = <docs website, if any>

Just a small gripe

Missing precision on x axis values, making them identical

Hello Olav,
I have noticed a small problem when displaying the x axis values. The values seem to be rounded too much making them identical and equal to 0. It seems to happen when one value is positive, the other negative and the values are close to 0 (+-0.01) I included screenshots of it.

PS: uniplot feels great, keep it up!

Screenshot 2021-01-22 at 16 58 48

Screenshot 2021-01-22 at 17 08 59

Configurable move / zoom keys

After using uniplot now for a couple days, I found myself using the interactive mode quite often for some simple EDA on remote resources. However, I've been struggling a bit with the h/j/k/l key combinations for moving the bounding box ("struggling" is perhaps a too strong word here ^^), so I've been wondering if you would be up for having this configurable. If this option existed, I would change it to w/a/s/d.

The Options dataclass could be a good place for that, however, the question is whether this should be configurable per plot/histogram() call (1), or a global setting (2).

I don't believe people would need to change this behavior from plot to plot, so option 2 could make more sense here. In this case, a ClassVar on Options would already do the trick, allowing for (e.g.)

import uniplot
uniplot.Options.move_keys = "wasd"
uniplot.plot(...)

(just as an example, a proper setter is of course preferable here to change the class var)

Support for using datetime values for x axis labels

Hi again @olavolav. If I am not wrong, currently there is support for only using Number Datatypes on both the x and y axes. However, while performing time series analysis and plotting trends for the time, we often need to mention the time(month/ date etc.) as a string. I am looking for something similar to this but on the terminal.
image

I dont think that you need to perform any sorting for the date and such internally and we can probably mandate that the user itself sorts the list prior to plotting. Can this be supported?

Feature request: Boxplot

I'd like to plot boxplots on the terminal along with support for multiple boxplots alongside other boxplots

Extra lines are drawn that shouldn't be there

To Reproduce:

>>> plot(xs=[1,1], ys=[0,1], lines=True, x_min=3, x_max=6)
┌────────────────────────────────────────────────────────────┐
│                    ▖                                       │ 1.0
│                    ▌                                       │ 
│                    ▌                                       │ 
│                    ▌                                       │ 
│                    ▌                                       │ 0.7
│                    ▌                                       │ 
│                    ▌                                       │ 
│                    ▌                                       │ 
│                    ▌                                       │ 0.5
│                    ▌                                       │ 
│                    ▌                                       │ 
│                    ▌                                       │ 
│                    ▌                                       │ 0.3
│                    ▌                                       │ 
│                    ▌                                       │ 
│                    ▌                                       │ 
│▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▌▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁│ 0.0
└────────────────────────────────────────────────────────────┘
 3                                                          6

Obviously there should not be anything drawn in this view.

Here, the correct line is drawn, but also weird other ones. In interactive mode this line appears once the real one is out of view.

Requesting Support for Plotting Line Graphs

Hi Olav. Appreciate the great work with this project. Found this quite useful in logging some data graphically to the terminal in a few of my Data Science projects.
Here is a recommendation for a new feature that can be added. I understand that there is currently support for plotting Scatter Plots and Histograms in Uniplot. Would be great if support for plotting Line Graphs was also added to visualize the trend of data. Kindly look into the possibility of doing this.
Thanks.

Incorrect centering of labels with units

See this example:

>>> plot([1,3,2], height=2)
┌────────────────────────────────────────────────────────────┐
│                              ▘                            ▗│ 3
│▖                                                           │ 1
└────────────────────────────────────────────────────────────┘
 1                             2                            3
>>> plot([1,3,2], height=2, x_unit=" microns")
┌────────────────────────────────────────────────────────────┐
│                              ▘                            ▗│ 3
│▖                                                           │ 1
└────────────────────────────────────────────────────────────┘
 1 microns                     2 microns                    3 microns

What should happen is that the labels are centered, including the units.

Fill area under curve

This was on the roadmap but have not heard anyone actually request it. So I'll leave the prototypical hack here as an issue in case anyone wants to actually have it.

So in theory we could have an option like y_fill_level that enables filling the are between the points and a given vertical level, usually the zero line.

It might look something like:

plot(ys, title="Sine wave", y_fill_level=-2.5)
                          Sine wave
┌────────────────────────────────────────────────────────────┐
│                                                    ▟█▙     │ 
│                                                   ▗███▌    │ 
│                                       ▗██▖        ▟████    │ 
│                                       ▟███       ▗█████▌   │ 2
│                           ▟█▙        ▗████▌      ▐██████   │ 
│                          ▐███▖       ▟█████      ███████▌  │ 
│              ▗██▖        █████      ▗██████▌    ▐████████  │ 
│              ███▙       ▗█████▖     ▐██████▙    ▟████████▌ │ 
│  ▟█▖        ▐████▖      ▟█████▙     ████████▖  ▗██████████▄│ 1
│ ▐███▖       █████▙      ███████▖   ▗████████▙  ▟███████████│ 
│ ████▙      ▗██████▖    ▐███████▙   ▟█████████▙▟████████████│ 
│▐█████▖     ▐██████▌    █████████▖ ▗████████████████████████│ 
│▟█████▌     ████████   ▗██████████▄█████████████████████████│ 
│███████────▐████████▙──▟████████████████████████████████████│ 0
│███████▌   ██████████▙▟█████████████████████████████████████│ 
│████████  ▐█████████████████████████████████████████████████│ 
│████████▙▄██████████████████████████████████████████████████│ 
└────────────────────────────────────────────────────────────┘
         100       200       300       400       500       600

And then with colors it might look like:
Screen Shot 2021-05-01 at 18 18 25

Let me know if this feature would be useful.

Crash after zooming

To reproduce:

from uniplot import plot, histogram
import numpy as np  # type: ignore

# Exception when zooming in

xs = np.array(
    [
        0,
        1,
        2,
        3,
        4,
        5,
        6,
        7,
        8,
        9,
        10,
        11,
        12,
        13,
        14,
        15,
        16,
        17,
        18,
        19,
        20,
        21,
        22,
        23,
        24,
        25,
        26,
        27,
        28,
        29,
        30,
        31,
        32,
        33,
        34,
        35,
        36,
        37,
        38,
        39,
        40,
        41,
        42,
        43,
        44,
        45,
        46,
        47,
        48,
        49,
        50,
        51,
        52,
        53,
        54,
        55,
        56,
        57,
        58,
        59,
        60,
        61,
        62,
        63,
        64,
        65,
        66,
        67,
        68,
        69,
        70,
        71,
        72,
        73,
        74,
        75,
        76,
        77,
        78,
        79,
        80,
        81,
        82,
        83,
        84,
        85,
        86,
        87,
        88,
        89,
        90,
        91,
        92,
        93,
        94,
        95,
        96,
        97,
        98,
        99,
        100,
        101,
        102,
        103,
        104,
        105,
        106,
        107,
        108,
        109,
        110,
        111,
        112,
        113,
        114,
        115,
        116,
        117,
        118,
        119,
        120,
        121,
        122,
        123,
        124,
        125,
        126,
        127,
        128,
        129,
        130,
        131,
        132,
        133,
        134,
        135,
        136,
        137,
        138,
        139,
        140,
        141,
        142,
        143,
        144,
        145,
        146,
        147,
        148,
        149,
        150,
        151,
        152,
        153,
        154,
        155,
        156,
        157,
        158,
        159,
        160,
        161,
        162,
        163,
        164,
        165,
        166,
        167,
        168,
        169,
        170,
        171,
        172,
        173,
        174,
        175,
        176,
        177,
        178,
        179,
        180,
        181,
        182,
        183,
        184,
        185,
        186,
        187,
        188,
        189,
        190,
        191,
        192,
        193,
        194,
        195,
        196,
        197,
        198,
        199,
        200,
        201,
        202,
        203,
        204,
        205,
        206,
        207,
        208,
        209,
        210,
        211,
        212,
        213,
        214,
        215,
        216,
        217,
        218,
        219,
        220,
        221,
        222,
        223,
        224,
        225,
        226,
        227,
        228,
        229,
        230,
        231,
        232,
        233,
        234,
        235,
        236,
        237,
        238,
        239,
        240,
        241,
        242,
        243,
        244,
        245,
        246,
        247,
        248,
        249,
        250,
        251,
        252,
        253,
        254,
        255,
        256,
        257,
        258,
        259,
        260,
        261,
        262,
        263,
        264,
        265,
        266,
        267,
        268,
        269,
        270,
        271,
        272,
        273,
        274,
        275,
        276,
        277,
        278,
        279,
        280,
        281,
        282,
        283,
        284,
        285,
        286,
        287,
        288,
        289,
        290,
        291,
        292,
        293,
        294,
        295,
        296,
        297,
        298,
        299,
        300,
        301,
        302,
        303,
        304,
        305,
        306,
        307,
        308,
        309,
        310,
        311,
        312,
        313,
        314,
        315,
        316,
        317,
        318,
        319,
        320,
        321,
        322,
        323,
        324,
        325,
        326,
        327,
        328,
        329,
        330,
        331,
        332,
        333,
        334,
        335,
        336,
        337,
        338,
        339,
        340,
        341,
        342,
        343,
        344,
        345,
        346,
        347,
        348,
        349,
        350,
        351,
        352,
        353,
        354,
        355,
        356,
        357,
        358,
        359,
        360,
        361,
        362,
        363,
        364,
        365,
        366,
        367,
        368,
        369,
        370,
        371,
        372,
        373,
        374,
        375,
        376,
        377,
        378,
        379,
        380,
        381,
        382,
        383,
        384,
        385,
        386,
        387,
        388,
        389,
        390,
        391,
        392,
        393,
        394,
        395,
        396,
        397,
        398,
        399,
        400,
        401,
        402,
        403,
        404,
        405,
        406,
        407,
        408,
        409,
        410,
        411,
        412,
        413,
        414,
        415,
        416,
        417,
        418,
        419,
        420,
        421,
        422,
        423,
        424,
        425,
        426,
        427,
        428,
        429,
        430,
        431,
        432,
        433,
        434,
        435,
        436,
        437,
        438,
        439,
        440,
        441,
        442,
        443,
        444,
        445,
        446,
        447,
        448,
        449,
        450,
        451,
        452,
        453,
        454,
        455,
        456,
        457,
        458,
        459,
        460,
        461,
        462,
        463,
        464,
        465,
        466,
        467,
        468,
        469,
        470,
        471,
        472,
        473,
        474,
        475,
        476,
        477,
        478,
        479,
        480,
        481,
        482,
        483,
        484,
        485,
        486,
        487,
        488,
        489,
        490,
        491,
        492,
        493,
        494,
        495,
        496,
        497,
        498,
        499,
    ]
)
ys = np.array(
    [
        1.26230459e00,
        3.59321301e-01,
        2.11936647e00,
        1.84432132e00,
        2.27899071e00,
        1.51661172e00,
        1.95712695e-01,
        1.64582244e00,
        1.19080132e00,
        1.77906596e00,
        2.60834568e00,
        4.01352512e00,
        1.12257450e00,
        -2.38223520e-01,
        3.17199023e-01,
        2.85413316e-01,
        9.91733067e-01,
        1.84263384e00,
        2.32001561e00,
        1.33347914e00,
        3.46571661e-01,
        1.34794460e00,
        1.36144011e00,
        2.22913711e00,
        2.95592602e00,
        3.01213057e00,
        1.87905661e00,
        4.10827814e-01,
        -2.75564854e-01,
        1.03768731e00,
        -3.97770275e-01,
        3.06930582e00,
        2.78850709e00,
        1.48173807e00,
        -4.55744704e-03,
        -1.32975609e00,
        6.36077517e-02,
        1.83738438e00,
        1.68082395e00,
        1.39683868e00,
        -9.97108469e-02,
        -9.49959243e-01,
        7.88987944e-01,
        5.23096813e-01,
        1.79377985e00,
        2.56523643e00,
        1.65300403e00,
        1.40698126e00,
        7.48265081e-01,
        6.23696401e-01,
        9.13088969e-01,
        7.17841682e-01,
        1.76776214e00,
        3.85539288e00,
        1.44986447e00,
        2.91732462e-02,
        1.34081560e00,
        6.29367473e-01,
        1.89256668e00,
        -5.01236350e-01,
        2.44245545e00,
        -3.76219798e-01,
        -1.52341955e00,
        6.89569262e-02,
        3.47522530e-01,
        -1.68230067e-01,
        1.34471069e00,
        1.18431856e00,
        1.31349600e00,
        7.29997833e-01,
        2.89225012e-01,
        -2.80413712e00,
        7.50533432e-01,
        8.71114431e-01,
        7.07190831e-01,
        3.17740131e00,
        5.86036160e-01,
        5.90711279e-01,
        -7.22011344e-01,
        -1.50789690e-01,
        1.50888043e00,
        3.91049296e-01,
        2.35969482e00,
        1.08970815e00,
        1.42594895e00,
        4.96137247e-01,
        1.30358513e00,
        3.34551072e00,
        1.93665667e00,
        1.53050683e00,
        2.36212454e00,
        -5.24698604e-01,
        4.42035630e-02,
        -9.42400877e-01,
        9.51652062e-01,
        -6.94684749e-01,
        2.91913781e00,
        4.31538812e-02,
        -1.24747396e00,
        7.96053706e-02,
        1.87125758e00,
        3.24216046e00,
        1.21241355e00,
        1.18453587e00,
        -6.06840947e-01,
        -5.66081726e-01,
        1.95866564e00,
        1.73761292e-01,
        1.45443360e00,
        3.12741942e00,
        2.18546158e00,
        3.38033204e-01,
        7.39796805e-02,
        -4.12367686e-01,
        2.09752078e00,
        2.94173384e00,
        1.43576006e00,
        2.35233888e00,
        1.75026987e-01,
        -7.96761454e-01,
        1.16392155e00,
        3.95625636e-01,
        3.25318881e00,
        1.50728811e00,
        4.19976468e00,
        2.68370507e-01,
        2.61967644e00,
        -8.89491321e-02,
        2.55987916e00,
        2.56399322e00,
        9.51770979e-01,
        6.74653511e-01,
        2.33729281e-01,
        -7.14686280e-01,
        -2.67159716e-01,
        1.13894794e00,
        3.23252390e00,
        1.33774678e00,
        1.31868005e00,
        1.81951904e-01,
        4.79242635e-01,
        2.15532864e-01,
        6.92885478e-01,
        1.70927123e00,
        1.32722492e00,
        1.44586826e00,
        1.29820650e00,
        3.99065294e-01,
        -5.78380524e-01,
        9.27519202e-01,
        2.47403927e-01,
        1.55674871e00,
        -3.25379422e-01,
        1.09442721e00,
        -4.74897587e-01,
        1.93365775e00,
        1.41704079e00,
        2.91712317e00,
        2.66207768e00,
        1.84139843e-01,
        1.37767813e-01,
        1.25142357e00,
        4.84057548e-01,
        6.07245680e-01,
        3.30181350e-01,
        2.43432229e00,
        2.56402791e00,
        -6.93171018e-01,
        6.68779033e-01,
        -1.94396361e-01,
        1.51260020e00,
        2.49096620e00,
        2.45031139e00,
        3.03096170e-01,
        -8.18876084e-01,
        8.19588735e-01,
        -1.17728460e00,
        -1.16854500e00,
        2.44811633e00,
        1.93316841e00,
        1.37030049e00,
        7.81292142e-01,
        4.01495947e-01,
        1.47579864e-01,
        -2.84856788e-01,
        1.98363074e00,
        2.19940360e00,
        -8.05836667e-01,
        1.46269262e00,
        -7.71479430e-01,
        -4.29736882e-01,
        1.49405237e00,
        1.83036686e00,
        9.27646287e-01,
        1.42684947e00,
        -1.47479979e00,
        -2.83542544e00,
        -1.32329789e00,
        8.63657805e-01,
        1.67849080e00,
        2.90746670e-01,
        1.21004861e00,
        -1.20775413e00,
        -5.31279246e-01,
        1.56967687e00,
        1.83278302e00,
        9.72991848e-01,
        1.67934543e00,
        1.94689352e00,
        -1.29059489e00,
        -1.66424333e-01,
        6.79751734e-01,
        1.91516968e00,
        1.71575116e00,
        1.79466158e00,
        5.07323181e-01,
        6.24431305e-01,
        1.25871938e00,
        9.73003775e-01,
        1.83284056e00,
        7.67068188e-01,
        2.16195802e00,
        1.97370305e00,
        7.27160897e-01,
        -9.71488218e-01,
        -8.58690312e-01,
        -3.67525205e-01,
        1.29494233e00,
        7.18195673e-02,
        1.21326802e00,
        -7.58598785e-01,
        -1.06418506e-03,
        -3.60541127e-01,
        5.97630287e-01,
        1.16314252e00,
        2.79888774e00,
        3.17366401e00,
        8.46983160e-01,
        1.71412642e-02,
        -5.94253205e-01,
        1.10030645e-01,
        8.48605322e-01,
        1.60590771e00,
        1.51386287e00,
        -7.66986890e-01,
        3.71606231e-01,
        9.31114992e-01,
        1.14051595e00,
        3.12671250e00,
        8.41910255e-01,
        1.81572098e00,
        7.26485448e-01,
        9.54109141e-01,
        -7.01049465e-01,
        -7.08966723e-01,
        1.84269535e00,
        2.23904728e00,
        1.04671627e00,
        3.85234747e-02,
        -4.04382967e-01,
        7.65336840e-01,
        7.72256692e-01,
        1.39904849e00,
        1.49380494e00,
        1.02689147e00,
        7.66556348e-01,
        6.45355391e-01,
        5.92087646e-01,
        1.45512657e00,
        8.99221323e-01,
        2.24730476e00,
        1.83258046e00,
        1.76767850e00,
        -8.32995347e-02,
        1.43100675e00,
        1.42191705e-01,
        2.27576545e00,
        3.39549232e00,
        3.35252919e00,
        1.48749067e00,
        -1.17012953e00,
        -6.15039264e-01,
        9.25848706e-01,
        8.39612122e-01,
        3.49473756e00,
        3.62672699e00,
        7.11679401e-01,
        -6.21133647e-01,
        -1.71974130e-01,
        2.19582351e-01,
        1.70029203e00,
        4.97072898e-01,
        3.07661373e00,
        5.89705127e-01,
        -3.85557180e-01,
        -1.21627747e-01,
        6.88094658e-01,
        2.08683855e00,
        2.04800796e00,
        3.67022420e-01,
        3.03847578e-02,
        2.12803068e-01,
        1.27382824e00,
        2.20525878e00,
        2.09729942e00,
        2.92745219e00,
        1.43501329e00,
        -1.00158984e00,
        -4.26869441e-01,
        2.38459396e-01,
        6.18281003e-01,
        2.86900336e00,
        5.26441897e-01,
        1.83471736e00,
        5.64276032e-01,
        -4.79185498e-02,
        1.56645081e00,
        1.90975688e00,
        1.96805054e00,
        1.32437211e00,
        1.54723551e00,
        2.97027599e00,
        8.23747319e-01,
        -1.07597824e00,
        1.29796781e-01,
        3.08261173e00,
        1.94024883e00,
        1.67053036e00,
        7.68453719e-01,
        2.53848214e-01,
        -2.71074406e-01,
        1.11041190e00,
        3.06171371e00,
        2.88915244e00,
        2.00362771e00,
        1.67907635e00,
        9.25318467e-01,
        -6.21558807e-01,
        3.77295621e-01,
        2.51130485e00,
        1.23662523e00,
        1.47239092e00,
        1.17058209e00,
        1.47667951e-01,
        1.33386697e-01,
        -4.53263981e-01,
        1.12631733e00,
        3.26298892e00,
        2.35568468e00,
        3.83027496e-01,
        -3.78093690e-02,
        6.37261226e-01,
        1.72890857e00,
        2.57274809e00,
        2.60905435e00,
        1.56994909e00,
        5.17535191e-01,
        3.77275665e-01,
        -3.45929860e-01,
        2.58949535e00,
        7.62669260e-01,
        3.47958346e00,
        1.83376087e00,
        3.34759101e-01,
        -1.39156268e-01,
        1.24690335e-01,
        1.07593646e00,
        1.77047871e00,
        1.18853328e00,
        8.68015144e-01,
        8.48988929e-01,
        -8.95110881e-01,
        1.07420642e-01,
        3.06363479e00,
        7.15866469e-01,
        1.66342966e00,
        2.57150732e00,
        -1.04277245e-01,
        -2.90886083e00,
        -1.00809760e00,
        7.93375194e-01,
        2.20504948e00,
        2.85967791e00,
        2.15743733e00,
        2.08510982e00,
        3.16493745e-01,
        -1.04790522e00,
        1.30076686e-01,
        1.47648939e00,
        9.65983115e-01,
        3.03133713e00,
        -2.24802033e00,
        -1.90839207e-01,
        1.41532791e00,
        7.77675677e-01,
        2.91494777e00,
        2.70474727e00,
        2.01074236e00,
        1.30244225e00,
        -4.91068641e-01,
        4.32498323e-01,
        1.95233060e00,
        3.07520214e00,
        3.78334096e00,
        3.35590562e00,
        -8.08053405e-01,
        4.51994781e-01,
        7.74504797e-01,
        3.52334793e-01,
        2.44854135e00,
        3.34811742e00,
        1.82352584e00,
        2.26330255e00,
        2.77269351e-01,
        6.07576157e-02,
        -2.01833711e-01,
        1.04185052e00,
        2.32538242e00,
        2.84038167e00,
        2.29044210e00,
        7.03146152e-01,
        -6.01907112e-01,
        1.80397234e00,
        1.98634086e00,
        1.22690644e00,
        3.21915541e00,
        -1.17284206e00,
        -1.54417786e00,
        9.18351626e-01,
        1.76980729e00,
        1.04351305e00,
        2.36195029e00,
        1.16500774e00,
        6.12450462e-01,
        -7.08609723e-01,
        1.04230824e00,
        1.70969447e00,
        2.64288913e00,
        2.34976952e-01,
        1.18716059e00,
        -6.61424108e-02,
        -1.20049369e00,
        -1.12993788e-01,
        7.55088949e-01,
        1.83416312e00,
        2.91320098e00,
        2.24328733e00,
        2.40555340e00,
        -8.20700873e-01,
        -2.63662670e-01,
        2.94146708e00,
        1.04753337e00,
        2.53330830e00,
        2.32237327e00,
        3.59879157e00,
        -8.70552383e-02,
        -1.59399066e00,
        5.19713176e-01,
        2.12543089e00,
        6.33612253e-01,
        6.34693702e-03,
        5.60397860e-01,
        1.11221859e00,
        5.75088199e-01,
        1.47442294e00,
        1.57493470e00,
        2.26755516e00,
        1.01931474e00,
        8.58035549e-01,
        6.32568766e-02,
        -9.93171533e-02,
        9.53238163e-01,
        -7.85355122e-02,
        2.21938966e00,
        -7.07804875e-01,
        1.67680863e00,
        -6.63675108e-01,
        8.64217983e-02,
        6.97749258e-01,
        1.31259744e00,
        2.59287989e00,
        1.56744990e00,
        7.89167355e-01,
        1.81647380e00,
        7.08114108e-02,
        4.20118710e-01,
        2.17202561e00,
        2.82122287e00,
        3.27621088e00,
        6.30451516e-01,
        9.99653246e-01,
        1.30341376e00,
        5.29974172e-01,
        2.89059099e00,
        1.37370641e00,
        1.23284225e00,
        9.20544746e-02,
        -2.13971697e00,
        6.64817992e-02,
        4.62250775e-01,
    ]
)

After zooming in a few times, it looks something like this:

┌────────────────────────────────────────────────────────────┐
│▐  ▐  █ ▐  ▖ ▟▟ █ ▐█    ▌    ▐▌▐▐    ▌▌▐▐ ▌ ▙▌ ▐ ▌▐ ▌▌▐▐▌▐  │ 1.7
│▐▐ ▐  █ ▐  ▌ ██ ▌▌▐▛▖   ▌  ▌ ▐▌▐▐    ▌▌▐▐ ▌ █▌ ▐ ▌▐▌▌▌▌▐▌▐▌▐│ 
│▐▐ ▐  █▖▐▙ █ ██ ▌▌▐▌▌   ▌  █ ▐▌▐▐ ▐ ▗▌▙▐▐ ▌ ▜▌ ▐ ▌▐▌▌▌▌▐▌▌▚▐│ 
│▐▐ ▐▚ █▌▞█ █ ██ ▌▌▐▌▌▗  ▌  █ ▐▌▐▐ ▐▌▐▌█▟▐ ▌▖▐▌ ▐ ▙▐▌▙▌▌▞▚▌▐▐│ 
│█▝ ▐▐ █▌▌█ █▌██ ▌▌█▌▌▐▌▐▌  █ ▟▌▐▐ ▌▌▐▌██▐ ▌▌▐▌ ▐ █▐▌█▌▌ ▐▌█▐│ 1.2
│█  ▐▐ █▌▌█ █▌▛█▐ █▌▌▌▐▙ ▌ ▐▐▐▐▌▐▐ ▌▌▐▌█▛▐ █▌▐▌ ▝▌█▐▌██▌▌▐▌█▐│ 
│█  ▐▐ ██▌▜ █▌▌▜▐ █▘▌▌▐█ ▌ ▐▐▐▐█▐▐▖▌▚▐▌█▌▐▐█▌▐▌  ▌█▐▌██▌▌▐▌█▐│ 
│█ ▐▐▐ ██▌▐ █▌▌▐▐▗█ ▌▌▐█ ▌▌▟▐▐▝▐▐▐▙▌▐▞ █▌▐▐▜▌▐▙  ▌█▐▌█▜▌▌▐▌█▐│ 
│█ ▐▐▝▖██▌▐ █▌▌▐▐▝█ ▌▌▐█▐ ▚▜▐▞ ▐▐▐█ ▝▌ █▌▐▐▐▌▐█ ▌▌█▐▘█▐▌▌▐▌█▐│ 0.6
│█ ▐▐ ▌██▌▐ █▌▌▐▐ ▌ ▌▌▐█▐ ▐▐▐▌ ▝▟▐█    ▜▌▐▐▐▌▐█▐▌▙▜▐ █▐▌▌▐▌▀▟│ 
│█ ▐▐ ▌██▌▐ █▌▌▐▐   ▌▌▐█▐ ▐▐▐▌  █▝█    ▐▌▐▐▐▌▐ █▌█▐▐▐ ▐▌▌▐▌ █│ 
│█▐▐▐ ▚██▌▐▐▛▌▌▐▐   ▌▌▞█▐▐▐▐▐▌  █ █    ▐▌▐▐▐▐▌ █▘█▝▐▐ ▐▌▌▐▌ █│ 
│█▝▟▐ ▐██▌▐▐▌▌▌▐▐   ▌▙▌█▐▐▐▞▐▌  █ █▗   ▐▘▖█▐▐▌▐█ █ ▐▐ ▐▌▌▐▌ █│ 0.1
│▌▔█▐▔▐▜█▌▐▐▔▌▙▐▐▔▔▔▔█▌▐█▐▐▌▐▌▔▔█▔█▐▔▔▔▐▔▌█▐▐▌▐█▔▌▔▐▐▔▝▌▌▐▌▔█│ 
│▌ █▌ ▐▐█▌▐▐ █▐ ▌    █▌▐█▐▐▌▐▌  █ █▐     ▌█▐▐▌ █ ▌ ▐▐   ▌▐▌ █│ 
│▌ █▌ ▝▝█▌▐▐ █▐ ▌    █▌▐█▐▐▌▐▌  █ ▛▐     ▌█▐▐▘ ▌ ▘ ▐▞   ▌▐▌ ▝│ 
│▌ █▌   █▌▐▐ █▐ ▌    ▐▌▐▘▐ ▌▐▌  █ ▌▐      █▐▐  ▘   ▝▌   ▘▐▌  │ -0.5
└────────────────────────────────────────────────────────────┘
 168                                                      332
Move h/j/k/l, zoom u/n, or r to reset. ESC/q to quit
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/olav/Desktop/Development/uniplot/uniplot/uniplot.py", line 48, in plot
    xs=series.xs, ys=series.ys, options=options
  File "/Users/olav/Desktop/Development/uniplot/uniplot/layer_assembly.py", line 24, in assemble_scatter_plot
    pixel_layer = layer_factory.render_points(xs=xs, ys=ys, options=options)
  File "/Users/olav/Desktop/Development/uniplot/uniplot/layer_factory.py", line 75, in render_points
    lines=options.lines,
  File "/Users/olav/Desktop/Development/uniplot/uniplot/pixel_matrix.py", line 125, in render
    # DEBUG
IndexError: index -167 is out of bounds for axis 1 with size 120

Histogram x-axis range ignored

Hi again,

after playing around a bit more with histograms, I noticed that the x-axis range is ignored in cases where the number of bins as well as min/max values are provided (histogram(data, bins=..., x_min=..., x_max=...)).

Here is a reproducer:

import numpy as np
from uniplot import histogram

data = np.random.uniform(0, 3, size=1000)
histogram(data, bins=4, x_min=-0.5, x_max=3.5)

# ->
┌────────────────────────────────────────────────────────────┐
│       ▐▀▀▀▀▀▀▀▀▀▀▜          ▐▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▌       │
│       ▐          ▐          ▐                      ▌       │
│       ▐          ▝▀▀▀▀▀▀▀▀▀▀▀                      ▌       │
│       ▐                                            ▌       │ 200
│       ▐                                            ▌       │
│       ▐                                            ▌       │
│       ▐                                            ▌       │
│       ▐                                            ▌       │
│       ▐                                            ▌       │
│       ▐                                            ▌       │
│       ▐                                            ▌       │ 100
│       ▐                                            ▌       │
│       ▐                                            ▌       │
│       ▐                                            ▌       │
│       ▐                                            ▌       │
│       ▐                                            ▌       │
│▁▁▁▁▁▁▁▐▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▌▁▁▁▁▁▁▁│ 0
└────────────────────────────────────────────────────────────┘
        0              1              2              3

The axis range is of course correct, but I would have expected that the left edge of the first bin and the right edge of the last bin landed on -0.5 and 3.5, respectively.

I could provide a PR, but I first wanted to check if the current behavior was intended.

Label choice does not always seem optimal

In the example of #15 actually it is curious that the .5 labels are not chosen by the algorithm.

>>> from uniplot.axis_labels.extended_talbot_labels import extended_talbot_labels
>>> extended_talbot_labels(x_min=-1.846526999372103, x_max=-0.1651564799721942, available_space=17, vertical_direction=True, verbose=True).render()
### exponent = 0 ###
(...)
### exponent = -1 ###
### j = 1 ###
### i = 0, q = 1 ###
Testing labels: [-1.8 -1.7 -1.6 -1.5 -1.4 -1.3 -1.2 -1.1 -1.  -0.9 -0.8 -0.7 -0.6 -0.5
 -0.4 -0.3 -0.2] => simplicity = 0.19999999999999996, coverage = 0.9940240106065467, density = -4.666666666666667, grid_alignment unknown => score_approx = -0.8514939973483636
Testing labels: [-1.8 -1.7 -1.6 -1.5 -1.4 -1.3 -1.2 -1.1 -1.  -0.9 -0.8 -0.7 -0.6 -0.5
 -0.4 -0.3 -0.2] => simplicity = 0.19999999999999996, coverage = 0.9940240106065467, density = -4.666666666666667, grid_alignment => 1, score = -0.8514939973483636
=> New best score 😀
### i = 1, q = 5 ###
Testing labels: [-1.4 -0.9 -0.4] => simplicity = 0.0, coverage = 0.549810354275108, density = 0.0, grid_alignment unknown => score_approx = 0.337452588568777
Testing labels: [-1.4 -0.9 -0.4] => simplicity = 0.0, coverage = 0.549810354275108, density = 0.0, grid_alignment => 1, score = 0.337452588568777
=> New best score 😀
(...)
### j = 5 ###
### i = 0, q = 1 ###
Testing labels: [-1.4 -0.9 -0.4] => simplicity = -3.8, coverage = 0.549810354275108, density = 0.0, grid_alignment unknown => score_approx = -1.5625474114312228
Testing labels: [-1.8 -1.3 -0.8 -0.3] => simplicity = -3.8, coverage = 0.9640122259435896, density = -0.33333333333333326, grid_alignment unknown => score_approx = -1.5589969435141025
Testing labels: [-1.7 -1.2 -0.7 -0.2] => simplicity = -3.8, coverage = 0.9598794169078467, density = -0.33333333333333326, grid_alignment unknown => score_approx = -1.5600301457730383
Testing labels: [-1.6 -1.1 -0.6] => simplicity = -3.8, coverage = 0.5580759723465938, density = 0.0, grid_alignment unknown => score_approx = -1.5604810069133515
Testing labels: [-1.5 -1.  -0.5] => simplicity = -3.8, coverage = 0.5893162650552402, density = 0.0, grid_alignment unknown => score_approx = -1.55267093373619

It seems odd that the simplicity for the intuitive choice of [-1.5, -1.0, -0.5] is negative.

Let's investigate, could be a bug.

Incorrect axis labels in rare cases

See here, the correct labels are computed in terms of floating point numbers [-1.4 -0.9 -0.4] but then the string labels are "-0.4", "-0.9" and "-1". The last one is wrong, should of course be "-1.4" so it is cut off at the wrong digit.

See this example:

>>> from uniplot.axis_labels.extended_talbot_labels import extended_talbot_labels
>>> extended_talbot_labels(x_min=-1.846526999372103, x_max=-0.1651564799721942, available_space=17, vertical_direction=True, verbose=True).render()
DEBUG: x_min = -1.846526999372103
DEBUG: x_max = -0.1651564799721942
DEBUG: simplicity = 0.19999999999999996, coverage = 0.9940240106065467, density = -4.666666666666667, grid_alignment = 1 => New best score 😀 = -0.9014939973483634 with labels = [-1.8 -1.7 -1.6 -1.5 -1.4 -1.3 -1.2 -1.1 -1.  -0.9 -0.8 -0.7 -0.6 -0.5
 -0.4 -0.3 -0.2]
DEBUG: simplicity = 0.0, coverage = 0.549810354275108, density = 0.0, grid_alignment = 1 => New best score 😀 = 0.337452588568777 with labels = [-1.4 -0.9 -0.4]
['', '', '-0.4', '', '', '', '', '-0.9', '', '', '', '', '-1', '', '', '', '']

Suggestion for speeding up large data

Nice project!

So basically I have noticed that plotting has linear speed,

range(10_000_000) took 10x as long to plot as range(1_000_000)


If you are aware of the max resolution, then you could imagine you can compress the data, without resulting in a different plot

One way (probably it's possible to come up with something much better), would be to perhaps fit 1000 linear regressions on sorted data of 10_000_000 data points and use that to e.g. compress 10_000_000 rows into 1_000_000 (or less) - whatever is needed for the solution, basically the sign could be "0=stay equal, -decrease, +increase"

I was able to fit 1000 regressions in 300ms, whereas the naive plotting went from 1s to 10s, so a huge speed-up would be possible if you are able to compress the data

Get a plot as a string

I'm working on a tool that I would love to be able to integrate uniplot into, but I'm running into a problem: I need to capture the output as a string so that I can display it elsewhere. Right now, uniplot.plot prints directly to stdout: https://github.com/olavolav/uniplot/blob/master/uniplot/uniplot.py#L74

I'm not sure how to square this with the interactive features implemented in that function. Perhaps a helper function could be extracted that returns the plot as a string? Then I could call that function from my tool to get the string that uniplot.plot would have displayed.

Happy to do the work on this if you can provide some guidance on how you'd like it implemented!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.