|
| 1 | +# unicode_plot.cr |
| 2 | + |
| 3 | +[](https://github.com/kojix2/unicode_plot/actions/workflows/test.yml) |
| 4 | + |
| 5 | +Unicode terminal plots for Crystal — a port of Julia's [UnicodePlots.jl](https://github.com/JuliaPlots/UnicodePlots.jl). |
| 6 | + |
| 7 | +The code was ported from Julia using an AI tool |
| 8 | + |
| 9 | +**UNDER CONSTRUCTION** Until the first version is released, this repository will be updated by force push. |
| 10 | + |
| 11 | +## Installation |
| 12 | + |
| 13 | +Add to your `shard.yml`: |
| 14 | + |
| 15 | +```yaml |
| 16 | +dependencies: |
| 17 | + unicode_plot: |
| 18 | + github: kojix2/unicode_plot |
| 19 | +``` |
| 20 | +
|
| 21 | +Then run `shards install`. |
| 22 | + |
| 23 | +## Usage |
| 24 | + |
| 25 | +```crystal |
| 26 | +require "unicode_plot" |
| 27 | +include UnicodePlot |
| 28 | +``` |
| 29 | + |
| 30 | +### Line plot |
| 31 | + |
| 32 | +```crystal |
| 33 | +x = (0..62).map { |i| i * Math::PI / 31.0 } |
| 34 | +y = x.map { |v| Math.sin(v) } |
| 35 | +puts lineplot(x, y, title: "sin(x)", xlabel: "x", ylabel: "sin(x)", color: :blue) |
| 36 | +``` |
| 37 | + |
| 38 | +### Scatter plot |
| 39 | + |
| 40 | +```crystal |
| 41 | +x1 = (1..15).map { Random.rand * 3.0 + 1.0 } |
| 42 | +y1 = (1..15).map { Random.rand * 3.0 + 1.0 } |
| 43 | +x2 = (1..15).map { Random.rand * 3.0 + 6.0 } |
| 44 | +y2 = (1..15).map { Random.rand * 3.0 + 6.0 } |
| 45 | +
|
| 46 | +p = scatterplot(x1, y1, name: "cluster A", color: :blue, |
| 47 | + title: "Two clusters", xlim: {0.0, 11.0}, ylim: {0.0, 11.0}) |
| 48 | +scatterplot!(p, x2, y2, name: "cluster B", color: :red) |
| 49 | +puts p |
| 50 | +``` |
| 51 | + |
| 52 | +### Bar plot |
| 53 | + |
| 54 | +```crystal |
| 55 | +cities = ["Tokyo", "Delhi", "Shanghai", "São Paulo", "Mexico City"] |
| 56 | +popmill = [13.96, 16.79, 24.18, 12.33, 9.21] |
| 57 | +puts barplot(cities, popmill, title: "City populations", xlabel: "population [mil]") |
| 58 | +``` |
| 59 | + |
| 60 | +You can also pass a `Hash(String, Float64)` directly (sorted by key): |
| 61 | + |
| 62 | +```crystal |
| 63 | +puts barplot({"Ruby" => 95.0, "Python" => 98.0, "Crystal" => 72.0}, title: "Scores") |
| 64 | +``` |
| 65 | + |
| 66 | +### Histogram |
| 67 | + |
| 68 | +```crystal |
| 69 | +data = (1..500).map { Random.rand * 10.0 } |
| 70 | +puts histogram(data, title: "Uniform [0, 10)", nbins: 15) |
| 71 | +``` |
| 72 | + |
| 73 | +### Multiple series / incremental plots |
| 74 | + |
| 75 | +All plot types support a mutating `!` variant for adding series to an existing plot: |
| 76 | + |
| 77 | +```crystal |
| 78 | +x = (1..20).map(&.to_f) |
| 79 | +p = lineplot(x, x.map { |v| Math.sqrt(v) }, name: "√x", color: :green, title: "Functions") |
| 80 | +lineplot!(p, x, x.map { |v| Math.log(v) }, name: "ln(x)", color: :red) |
| 81 | +puts p |
| 82 | +``` |
| 83 | + |
| 84 | +### Options |
| 85 | + |
| 86 | +| Option | Description | |
| 87 | +|---|---| |
| 88 | +| `title` | Plot title | |
| 89 | +| `xlabel` / `ylabel` | Axis labels | |
| 90 | +| `xlim` / `ylim` | Axis limits as `{min, max}` tuple | |
| 91 | +| `color` | Line/point color (`:red`, `:blue`, `:green`, `:cyan`, `:magenta`, `:yellow`, `:normal`) | |
| 92 | +| `name` | Series name (shown in legend) | |
| 93 | +| `xscale` / `yscale` | Scale function (`:log2`, `:log10`, or a `Proc(Float64, Float64)`) | |
| 94 | +| `width` / `height` | Canvas size in characters | |
| 95 | +| `canvas` | Canvas type (`:braille`, `:block`, `:ascii`) | |
| 96 | + |
| 97 | +See `examples/` for runnable demos. |
| 98 | + |
| 99 | +## License |
| 100 | + |
| 101 | +MIT — see [LICENSE](LICENSE). |
0 commit comments