Skip to content

Commit 031c1ea

Browse files
authored
Make show use UnicodePlots instead (#50)
* unicode plot first version lol lol lol * add proper methods for show. * backend-dependent printing and default color = cyan * changelog for 0.9 and better name for the plotting function, hopefully.
1 parent 186a7f3 commit 031c1ea

File tree

4 files changed

+119
-10
lines changed

4 files changed

+119
-10
lines changed

NEWS.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# RecurrenceAnalysis.jl News
22

3+
## v0.9.0
4+
- Recurrence matrices are printed as a plot using `UnicodePlots`. See `textrecurrenceplot`.
5+
6+
## v0.8.0 - v0.8.7
7+
- Big documentation improvements
8+
- Changes to return values for various rqa functions
9+
- Functions that return recurrence structure histograms
10+
- Updated and more tests
11+
- Performance improvements
12+
313
## v0.7.0
414
* All `recurrencematrix` have been deprecate to `RecurrenceMatrix` which
515
create a dedicated struct for each kind of matrix.

REQUIRE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ julia 0.7
22
Distances 0.7.0
33
DelayEmbeddings 0.1.0
44
StaticArrays
5+
UnicodePlots

src/matrices.jl

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -104,23 +104,15 @@ end
104104

105105
function Base.summary(R::AbstractRecurrenceMatrix)
106106
N = nnz(R.data)
107-
return "$(nameof(typeof(R))) of size $(size(R.data)) with $N entries:"
108-
end
109-
function Base.show(io::IO, R::AbstractRecurrenceMatrix)
110-
s = sprint(io -> show(IOContext(io, :limit=>true), MIME"text/plain"(), R.data))
111-
s = split(s, '\n')[2:end]
112-
s = [replace(line, "= true"=>"", count=1) for line in s]
113-
s = join(s, '\n')
114-
tos = summary(R)*"\n"*s
115-
println(io, tos)
107+
return "$(nameof(typeof(R))) of size $(size(R.data)) with $N entries"
116108
end
117109

118110
# Propagate used functions:
119111
begin
120112
extentions = [
121113
(:Base, (:getindex, :size, :length, :view, :iterate)),
122114
(:LinearAlgebra, (:diag, :triu, :tril, :issymmetric)),
123-
(:SparseArrays, (:nnz, :rowvals, :nzrange))
115+
(:SparseArrays, (:nnz, :rowvals, :nzrange, :nonzeros))
124116
]
125117
for (M, fs) in extentions
126118
for f in fs
@@ -309,3 +301,17 @@ function JointRecurrenceMatrix(x, y, ε; kwargs...)
309301
end
310302
return JointRecurrenceMatrix(rm1.data .* rm2.data)
311303
end
304+
305+
#######################
306+
# Pretty printing
307+
#######################
308+
function oldshow(io::IO, R::AbstractRecurrenceMatrix)
309+
s = sprint(io -> show(IOContext(io, :limit=>true), MIME"text/plain"(), R.data))
310+
s = split(s, '\n')[2:end]
311+
s = [replace(line, "= true"=>"", count=1) for line in s]
312+
s = join(s, '\n')
313+
tos = summary(R)*"\n"*s
314+
println(io, tos)
315+
end
316+
317+
Base.show(io::IO, R::AbstractRecurrenceMatrix) = println(io, summary(R))

src/plot.jl

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,92 @@
1+
#########################################
2+
# Text-based plotting
3+
#########################################
4+
"""
5+
scatterdata(R::ARM) -> xs, ys
6+
Transform the data of a recurrence matrix to scatter data `xs, ys`.
7+
"""
8+
function scatterdata(R::ARM) # TODO: scan every ÷100 elements depending on size?
9+
rows = rowvals(R)
10+
is = zeros(Int, nnz(R))
11+
js = zeros(Int, nnz(R))
12+
k = 1;
13+
m, n = size(R)
14+
for j = 1:n
15+
for i in nzrange(R, j)
16+
is[k] = j
17+
js[k] = rows[i]
18+
k += 1
19+
end
20+
end
21+
return is, js
22+
end
23+
24+
using UnicodePlots
25+
export textrecurrenceplot
26+
27+
textrecurrenceplot(R::ARM; kwargs...) = textrecurrenceplot(stdout, R::ARM; kwargs...)
28+
29+
"""
30+
textrecurrenceplot([io,] R; minh = 25, maxh = 0.5, ascii, kwargs...) -> u
31+
32+
Obtain a text-scatterplot representation of a recurrence matrix `R` to be displayed in
33+
`io` (by default `stdout`). The matrix spans at minimum `minh` rows and at maximum
34+
`maxh*displaysize(io)[1]` (i.e. by default half the display).
35+
As we always try to plot in equal aspect ratio, if the width of the plot is even less,
36+
the minimum height is dictated by the width.
37+
38+
The keyword `ascii::Bool` can ensure that all elements of the plot are ASCII characters
39+
(`true`) or Unicode (`false`).
40+
41+
The rest of the `kwargs` are propagated into `UnicodePlots.scatterplot`.
42+
43+
Internally this function calls `RecurrenceAnalysis.scatterdata` to transform
44+
a recurence matrix into scatter data.
45+
"""
46+
function textrecurrenceplot(io::IO, R::ARM; minh = 25, maxh = 0.5, ascii = nothing, kwargs...)
47+
@assert maxh 1
48+
h, w = displaysize(io)
49+
h = max(minh, round(Int, maxh * h)) # make matrix as long as half the screen (but not too short)
50+
s = 2.4 # scale that visually brings width and height to equal aspect ratio
51+
if w < round(Int, h*s) # ensure equal aspect ratio
52+
h = round(Int, w/s)
53+
else
54+
w = round(Int, h*s)
55+
end
56+
57+
is, js = scatterdata(R)
58+
n, m = size(R)
59+
60+
if ascii == true
61+
asciidef = (border = :ascii, canvas = DotCanvas)
62+
elseif ascii == false
63+
asciidef = (border = :solid, canvas = BrailleCanvas)
64+
#default:
65+
elseif ascii == nothing
66+
# TODO: always use ascii on Jupyter
67+
if (isdefined(Main, :Juno) && Main.Juno.isactive()) || !Sys.iswindows()
68+
asciidef = (border = :solid, canvas = BrailleCanvas)
69+
else
70+
asciidef = (border = :ascii, canvas = DotCanvas)
71+
end
72+
end
73+
74+
# TODO: Change limits to tuples instead of arrays
75+
UnicodePlots.scatterplot(
76+
is, js; xlim = [1, n], ylim = [1, m], title = summary(R), labels = false,
77+
color = :cyan, width = w, height = h, asciidef..., kwargs...
78+
)
79+
end
80+
81+
function Base.show(io::IO, ::MIME"text/plain", R::ARM)
82+
a = textrecurrenceplot(io, R)
83+
show(io, a)
84+
end
85+
86+
#########################################
87+
# Transform to full plotting
88+
#########################################
89+
190
# Check the assigned width and height of the plot to ensure that they are
291
# approximately proportional to the matrix size
392
function checkgridsize(width::T, height::T, dims::Tuple{T,T}) where T<:Integer
@@ -42,6 +131,9 @@ grayscale image. By default it returns a matrix with the same size as `x`,
42131
but switched axes, containing "black" values in the cells that represent recurrent points,
43132
and "white" values in the empty cells.
44133
134+
**This function does not do any plotting!** You have to use the return value with
135+
the plotting library of your choice.
136+
45137
The numeric codes for black and white are given in a 2-element tuple as a second
46138
optional argument. Its default value is `(0.0, 1.0)`, i.e. black is coded as `0.0`
47139
(no brightness) and white as `1.0` (full brightness). The type of the elements

0 commit comments

Comments
 (0)