:- lib(os_lib).
:- lib(real).
:- lib(options).
:- lib(debug_call).
:- lib(mtx).
:- lib( stoics_lib:kv_decompose/3 ).
:- lib( stoics_lib:list_proportions/3 ).
:- lib( stoics_lib:holds/2 ).
:- lib( stoics_lib:io_lines/2 ).
:- lib( stoics_lib:en_list/2 ).
:- lib( stoics_lib:portray_clauses/2 ).
:- lib( b_real:mtx_pheatmap/2 ).
svg_legend_defaults( Defs ) :-
Defs = [
cache(false),
clr_theme(org),
heatmaps(false),
postfix(leg),
postfix_mtx(mtx),
placement(bottom_right),
place_with_space(200),
place_with_decrement(20),
place_with_space_min(100),
upward(false)
].
:- debug( svg_legend ).
/** svg_legend( +FilesAndOpts )
Adds legend to svg files.
Atoms in Files and Opts are taken to be the files, and everything else is options.
See option atoms/1 in options_append/4.
If no Files are given, then svgs from current directory are used.
If one or more svg files with postfix fclr and a single svg with
postfix (os_postfix/2) exist, then those are taken as the inputs,
else all svgs are considered.
Opts
* cache(Cache=false)
whether to cache the intermediary (distance) matrices to files
* clr_theme(Theme=org)
alternatively use =bic= for bi-colour, =gates= for gated and =jyoti= for modern
* heatmaps(Hmaps=false)
whether to show matrix heatmaps
* postfix(Psfx=leg)
postfix for new svg
* postfix_mtx(Msfx=mtx)
postfix for the cache file of the intermediary matrices
* placement(Plc=bottom_right)
legend placement strategy. also implemented:
* at
see place_at_*
* on_rhs
extends the svg canvas by ??? and adds the legened at bottom right of extension
* place_at_x(X)
known to placement: at. mandatory for this placement. pos values work from top, neg from bottom
* place_at_y(y)
known to placement: at. mandatory for this placement. pos values work from left, neg from right
* place_with_space(Spc=200)
space parameter for strategies (known to bottom_right)
* place_with_decrement(Decr=20)
decrement parameter with the amount with which Spc is reduced if placement is not possible
* place_with_space_min(SpcMin=100)
mimimum space required
* upward(Upw=false)
set to _true_ for the y to interpreted as the bottom of the legend (currently only supported in jyoti)
==
?- cd(pack(sanger/examples/svg) ).
?- svg_legend( testo.svg ).
% pupsh svg_legend *gated.svg clr_theme=gates placement=at place_at_x=1000 place_at_y=-160
% pupsh svg_legend *fclr.svg placement=at place_at_x=1000 place_at_y=-90
% pupsh svg_legend tng/rea_smp-e10_fclr_gated.svg clr_theme=upward placement=at place_at_x=100 place_at_y=-1
% pupsh svg_legend tnx/rea_xsm-e1_fclr_gated.svg clr_theme=upward placement=at place_at_x=160 place_at_y=-1
ERROR: Unknown message: could_not_mtx_csv_file('tnx/rea_xsm-e1_fclr_gated.csv')
==
@author nicos angelopoulos
@version 0.1 2016/12/10
@version 0.2 2017/8/21, added placement: at (by passing distances, more or less properly)
@tbd optionise more
*/
svg_legend( Args ) :-
% spy( options_def_append ),
options_append( svg_legend, Args, Opts, [process(debug),atoms(Files)] ),
( Files = [] ->
svg_legend_dir( Opts )
;
maplist( svg_legend_file(Opts), Files )
).
svg_legend_dir( Opts ) :-
os_sel( os_files, ext(svg), Svgs ),
( ( include( os_postfix(fclr), Svgs, Fclrs ),
Fclrs \== [],
include( os_postfix(fisher), Svgs, [FisherSvg] )
)
->
ToLeg = [FisherSvg|Fclrs]
;
ToLeg = Svgs
),
include( svg_legend_file(Opts), ToLeg, _Successes ).
/*
svg_legend_file( Opts, File ) :-
memberchk( place_at_x(X), Opts ),
memberchk( place_at_y(Y), Opts ),
!,
svg_legend_place( Opts, File, X, Y ).
*/
svg_legend_file( Opts, File ) :-
debug( svg_legend, 'Svg input file: ~p', File ),
Mtx = m, W = w, H = h,
options( cache(Cache), Opts ),
options( placement(Plc), Opts ),
svg_legend_placement_requires_distance( Plc, Dist ),
svg_cache( Cache, File, Mtx, Dist, W, H, Opts ),
options( heatmaps(HmapsB), Opts ),
heatmaps( HmapsB, Mtx, H, W ),
Dims <- dim(Mtx),
Dims = [Y, X],
svg_legend_placement( Plc, Mtx, W, H, Y, X, Xi, Yi, Opts ),
svg_legend_abs_x_coord( Xi, X, Xa ),
svg_legend_abs_y_coord( Yi, Y, Ya ),
% NegYi is Yi - Y, % fixme: add/subt 1 ?
svg_legend_place( Opts, File, Xa, Ya ).
svg_legend_abs_x_coord( Rel, Edge, Abs ) :-
Rel < 0,
!,
Abs is Edge + Rel.
svg_legend_abs_x_coord( Rel, _Edge, Abs ) :-
Abs is Rel.
svg_legend_abs_y_coord( Rel, _Edge, Abs ) :-
Rel < 0,
!,
Abs is Rel.
svg_legend_abs_y_coord( Rel, Edge, Abs ) :-
Abs is Rel - Edge.
svg_legend_place( Opts, File, Xi, NegYi ) :-
debug( svg_legend, 'Placing at: ~w,~w', [Xi,NegYi] ),
options( postfix(Psfx), Opts ),
os_postfix( Psfx, File, Lile ),
io_lines( File, Lines ),
once( append(Unchanged,[Penu,Last],Lines) ),
options( clr_theme(Theme), Opts ),
options( upward(UpW), Opts ),
svg_add_lines( Theme, Xi, NegYi, UpW, File, AddLines ),
append( AddLines, [Penu,Last], NewTail ),
append( Unchanged, NewTail, New ),
io_lines( Lile, New ),
debug_call( svg_legend, wrote, Lile ).
/* fixme:
svg_add_lines( bic_gates_or_not, Xi, Yi, UpW, File, Add )
see: rearrange_muts-17.01.17_man
*/
gates_term_functor( Atom, Funcs ) :-
atomic( Atom ),
!,
Funcs = [].
gates_term_functor( Term, [Token|FuncNest] ) :-
Term =.. [Func|Args],
gates_term_functor_atom( Func, Token ),
maplist( gates_term_functor, Args, FuncNest ).
gates_term_functor_atom( o, or ) :- !.
gates_term_functor_atom( a, and ) :- !.
gates_term_functor_atom( n, not ) :- !.
gates_term_functor_atom( x, xor ) :- !,
throw( xor(ing) ).
gates_term_functor_atom( Oth, _ ) :- !,
throw( unknown_gate_functor(Oth) ).
svg_add_lines_gates( [], _Xi, Y, Y, [] ).
svg_add_lines_gates( [G|Gs], Xi, Yi, Y5, [Ln1,Ln2,Ln3,Ln4|GatesAtms] ) :-
svg_add_lines_gate( G, Xi, Yi, Ln1, Ln2, Ln3, Ln4 ),
Yj is Yi - 20,
svg_add_lines_gates( Gs, Xi, Yj, Y5, GatesAtms ).
svg_add_lines_gate( xor, _Xi, _Yi, _Yj, _L1, _L2, _L3, _L4 ) :-
throw( xor(ing) ).
svg_add_lines_gate( not, Xi, Yi, NotL1, NotL2, NotL3, NotL4 ) :-
% NOT gate
NotTxX is Xi + 30,
NotTxY is Yi,
NotX is Xi + 17,
NotY is Yi - 5,
NotL1a = 'NOT gate',
NotL2 = 'LegNot',
NotL3a = '',
NotL4 = '',
atomic_list_concat( [NotL1a,NotTxX,NotL1b,NotTxY,NotL1c], NotL1 ),
atomic_list_concat( [NotL3a,NotX,NotL3b,NotY,NotL3c], NotL3 ).
svg_add_lines_gate( and, Xi, Yi, AndLat, AndMat, AndNat, Aat ) :-
% AND GATE
T1 = '',
T4 = '',
AndX is Xi + 30,
AndY is Yi,
AndTxt = 'AND gate',
AndMat = ' LegAND',
AndN1 = ' ',
Aat = '',
atomic_list_concat( [T1,AndX,T2,AndY,T3,AndTxt,T4], AndLat ),
atomic_list_concat( [AndN1,AndPoly,AndN2], AndNat ).
svg_add_lines_gate( or, Xi, Yi, Lat, Mat, Nat, Oat ) :-
% OR GATE
T1 = '',
T4 = '',
OrX is Xi + 30,
OrY is Yi,
OrTxt = 'OR gate',
Mat = ' LegOR',
N1 = ' ',
Oat = '',
atomic_list_concat( [T1,OrX,T2,OrY,T3,OrTxt,T4], Lat ),
atomic_list_concat( [N1,Poly,N2], Nat ).
gates_sort( GatesBag, Gates ) :-
sort( GatesBag, GatesOrd ),
reverse( GatesOrd, GatesInRev ),
( select(not,GatesInRev,GatesNoNot) ->
Gates = [not|GatesNoNot]
;
Gates = GatesInRev
).
svg_line_segs_as( A1, A2, A3, A4 ) :-
A1 = '',
A4 = ''.
svg_line_segs_bs( B1, B2, B3 ) :-
B1 = ''.
svg_add_lines_compos( [], _File, _Xi, _Xt, _Yi, _Dir, [] ).
svg_add_lines_compos( [C|Cs], File, Xi, Xt, Yi, Dir, [Lns|TLns] ) :-
svg_add_lines_compo( C, File, Xi, Xt, Yi, IncY, Lns ),
Expr =.. [Dir,Yi,IncY],
Yj is Expr,
% Yj is Yi + IncY,
svg_add_lines_compos( Cs, File, Xi, Xt, Yj, Dir, TLns ).
svg_add_lines_compo( slide, _File, Xi, Xt, Yi, 20, [I,J] ) :-
% compo: slide
svg_line_segs_as( A1, A2, A3, A4 ),
L5 = 'Fisher test odds',
atomic_list_concat( [A1,Xt,A2,Yi,A3,L5,A4], '', I ),
J1 = '',
atomic_list_concat( [J1,Tx1,',',Ty1,' ',Tx2,',',Ty2,' ',Tx3,',',Ty3,J1b], J ).
svg_add_lines_compo( cooc, _File, Xi, Xt, Yi, 20, [A,E] ) :-
svg_line_segs_as( A1, A2, A3, A4 ),
svg_line_segs_bs( B1, B2, B3 ),
L1 = 'Co-occur (shown odds=4)',
atomic_list_concat( [A1,Xt,A2,Yi,A3,L1,A4], '', A ),
Ya is Yi - 5,
atomic_list_concat( [B1,'35978F',B2,Xi,',',Ya,B3], E ).
svg_add_lines_compo( muex, _File, Xi, Xt, Yi, 20, [A,E] ) :-
svg_line_segs_as( A1, A2, A3, A4 ),
svg_line_segs_bs( B1, B2, B3 ),
L2 = 'Mut.excl (shown odds=0.25)',
Ya is Yi - 5,
atomic_list_concat( [A1,Xt,A2,Yi,A3,L2,A4], '', A ),
atomic_list_concat( [B1,'BF812D',B2,Xi,',',Ya,B3], E ).
svg_add_lines_compo( pval, File, Xi, Xt, Yi, Pad, Lns ) :-
svg_line_segs_as( A1, A2, A3, A4 ),
svg_line_segs_bs( _B1, B2, _B3 ),
os_ext( _, csv, File, CsvFPrv ),
( exists_file(CsvFPrv) -> CsvF = CsvFPrv; os_postfix(gated,CsvF,CsvFPrv) ),
( mtx(CsvF,Mets) -> true; throw( could_not_mtx_csv_file(CsvF) ) ),
maplist( arg(3), Mets, Pvals ),
max_list( Pvals, MaxPv ),
( MaxPv < 0.05 -> % fixme: = means no significance...
Pad is 0,
Lns = []
;
Pad is 20,
L3 = '0.05 < q.val',
D1 = '',
atomic_list_concat( [D1,'35978F',B2,Xi,',',Yim,C3], DA ),
Xib is Xi + 14,
atomic_list_concat( [D1,'BF812D',B2,Xib,',',Yim,C3], DB ),
Lns = [C,DA,DB]
).
svg_add_lines_compo( node, File, Xi, Xt, Yi, 20, [G,H] ) :-
svg_line_segs_as( A1, A2, A3, A4 ),
svg_line_segs_bs( _B1, B2, B3 ),
L4 = '# of events (median=', L3b = ')',
atomic_list_concat( [FStem|_], '-', File ),
os_ext( dat, FStem, DatFile ),
write( 'dat.file'(DatFile) ), nl,
mtx( DatFile, DatMtx, sep(0' ) ),
mtx_value_column_frequencies( DatMtx, 1, Freqs ),
kv_decompose( Freqs, _Lbls, Times ),
TmMedian <- as.integer( median( Times ) ),
list_proportions( Times, Propos, to_range(r(1,4)) ),
NwMedian <- median( Propos ),
% Yl is Yk + 20,
atomic_list_concat( [A1,Xt,A2,Yi,A3,L4,TmMedian,L3b,A4], '', G ),
G1 = '',
atomic_list_concat( [D1,'35978F',B2,Xi,',',Ykm,C3], DA ),
Xib is Xi + 14,
atomic_list_concat( [D1,'BF812D',B2,Xib,',',Ykm,C3], DB ),
Atoms = [A,B,E,F, C,DA,DB, G,H, I,J]
),
L4 = '# of events (median=', L3b = ')',
atomic_list_concat( [FStem|_], '-', File ),
os_ext( dat, FStem, DatFile ),
write( 'dat.file'(DatFile) ), nl,
mtx( DatFile, DatMtx, sep(0' ) ),
mtx_value_column_frequencies( DatMtx, 1, Freqs ),
kv_decompose( Freqs, _Lbls, Times ),
TmMedian <- as.integer( median( Times ) ),
list_proportions( Times, Propos, to_range(r(1,4)) ),
NwMedian <- median( Propos ),
Yl is Yk + 20,
atomic_list_concat( [A1,Xt,A2,Yl,A3,L4,TmMedian,L3b,A4], '', G ),
G1 = '
svg_add_lines_compo( [slide], File, Xt, Xi, Yi, +, [I,J] ),
maplist( atom_codes, Atoms, Add ).
% maplist( atom_codes, [A,B,E,F, C,G], [ACs,BCs,ECs,FCs, CCs, GCs] ),
% Add = [ACs,ECs,BCs,FCs, CCs,GCs].
svg_add_lines( bic, Xi, Yi, _UpW, _File, Add ) :-
L1 = 'Co-occur',
L2 = 'Mut.excl',
A1 = '',
A4 = '',
Xt is Xi + 30,
atomic_list_concat( [A1,Xt,A2,Yi,A3,L1,A4], '', A ),
Yj is Yi + 20,
atomic_list_concat( [A1,Xt,A2,Yj,A3,L2,A4], '', B ),
B1 = '',
Ya is Yi - 5,
atomic_list_concat( [B1,'35978F',B2,Xi,',',Ya,B3], E ),
Yb is Yj - 5,
atomic_list_concat( [B1,'BF812D',B2,Xi,',',Yb,B3], F ),
maplist( atom_codes, [A,B,E,F], [ACs,BCs,ECs,FCs] ),
Add = [ACs,ECs,BCs,FCs].
svg_add_lines( gates, Xi, Yi, UpW, File, Add ) :-
T1 = '',
T4 = '',
% inter gate edge
InTxX is Xi + 30,
InTxY is Yi + 140,
InTxt = 'Inter gates edge',
B1 = '',
Ya is Yi + 135,
atomic_list_concat( [B1,'000000',B2,Xi,',',Ya,B3], I1atm ), % black
atomic_list_concat( [T1,InTxX,T2,InTxY,T3,InTxt,T4], I2atm ),
maplist( atom_codes, [I1atm,I2atm], [I1,I2] ),
% NOT gate
NotTxX is Xi + 30,
NotTxY is Yi + 120,
NotX is Xi + 17,
NotY is Yi + 115 ,
NotL1a = 'NOT gate',
NotL2 = 'LegNot',
NotL3a = '',
NotL4 = '',
atomic_list_concat( [NotL1a,NotTxX,NotL1b,NotTxY,NotL1c], NotL1 ),
atomic_list_concat( [NotL3a,NotX,NotL3b,NotY,NotL3c], NotL3 ),
maplist( atom_codes, [NotL1,NotL2,NotL3,NotL4], [Not1,Not2,Not3,Not4] ),
% OR GATE
OrX is Xi + 30,
OrY is Yi + 80,
OrTxt = 'OR gate',
Mat = ' LegOR',
N1 = ' ',
Oat = '',
atomic_list_concat( [T1,OrX,T2,OrY,T3,OrTxt,T4], Lat ),
atomic_list_concat( [N1,Poly,N2], Nat ),
maplist( atom_codes, [Lat, Mat, Nat, Oat], [LCs,MCs,NCs,OCs] ),
% AND GATE
AndX is Xi + 30,
AndY is Yi + 100,
AndTxt = 'AND gate',
AndMat = ' LegAND',
AndN1 = ' ',
atomic_list_concat( [T1,AndX,T2,AndY,T3,AndTxt,T4], AndLat ),
atomic_list_concat( [AndN1,AndPoly,AndN2], AndNat ),
maplist( atom_codes, [AndLat,AndMat,AndNat], [AndLCs,AndMCs,AndNCs] ),
svg_add_lines( org, Xi, Yi, UpW, File, OrgAdd ),
Add = [Not1,Not2,Not3,Not4,I1,I2,LCs,MCs,NCs,OCs,AndLCs,AndMCs,AndNCs,OCs|OrgAdd].
svg_add_lines( org, Xi, Yi, _UpW, _File, Add ) :-
L1 = 'Co-occur (signif)',
L2 = 'Mut.excl (signif)',
L3 = 'Co-occur',
L4 = 'Mut.excl',
A1 = '',
A4 = '',
Xt is Xi + 30,
atomic_list_concat( [A1,Xt,A2,Yi,A3,L1,A4], '', A ),
Yj is Yi + 20,
atomic_list_concat( [A1,Xt,A2,Yj,A3,L2,A4], '', B ),
Yk is Yj + 20,
atomic_list_concat( [A1,Xt,A2,Yk,A3,L3,A4], '', C ),
Yl is Yk + 20,
atomic_list_concat( [A1,Xt,A2,Yl,A3,L4,A4], '', D ),
B1 = '',
Ya is Yi - 5,
atomic_list_concat( [B1,'35978F',B2,Xi,',',Ya,B3], E ),
Yb is Yj - 5,
atomic_list_concat( [B1,'BF812D',B2,Xi,',',Yb,B3], F ),
Yc is Yk - 5,
% 4B5320, army green
% #008000, % Ao
atomic_list_concat( [B1,'008000',B2,Xi,',',Yc,B3], G ), % this and the one below were switched prior to 17.01.06
Yd is Yl - 5,
atomic_list_concat( [B1,'CC0000',B2,Xi,',',Yd,B3], H ),
%
maplist( atom_codes, [A,B,C,D], [ACs,BCs,CCs,DCs] ),
maplist( atom_codes, [E,F,G,H], [ECs,FCs,GCs,HCs] ),
Add = [ACs,ECs,BCs,FCs,CCs,GCs,DCs,HCs].
svg_legend_placement( at, _Mtx, _W, _H, _Y, _X, Xi, Yi, Opts ) :-
options( place_at_x(Xi), Opts ),
options( place_at_y(Yi), Opts ).
svg_legend_placement( bottom_right, Mtx, W, H, Y, X, Xi, Yi, Opts ) :-
options( place_with_space(Spc), Opts ),
options( place_with_decrement(Dcr), Opts ),
options( place_with_space_min(Smn), Opts ),
svg_bottom_right( Mtx, W, H, Y, X, Spc, Dcr, Smn, Xi, Yi ).
svg_bottom_right( Mtx, W, H, Y, X, Spc, _Dcr, _Smn, Xi, Yi ) :-
debug( svg_legend, 'Trying bottom_right with space: ~w', Spc ),
svg_bottom_right( Mtx, W, H, Y, X, Spc, Xi, Yi ),
debug( svg_legend, 'Committing to space: ~w', Spc ),
!.
svg_bottom_right( Mtx, W, H, Y, X, Spc, Dcr, Smn, Xi, Yi ) :-
New is Spc - Dcr,
Spc =< Smn, % fixme, error if this fails
svg_bottom_right( Mtx, W, H, Y, X, New, Dcr, Smn, Xi, Yi ).
svg_bottom_right( Mtx, W, H, Y, X, Xspc, Xi, Yi ) :-
Yspc is 36,
StartY is Y - Yspc,
StartX is X - Xspc,
svg_bottom_right( StartY, StartX, Yspc, Xspc, Mtx, W, H, Y, X, Xi, Yi ).
svg_bottom_right( Y, X, Yspc, Xspc, _Mtx, W, H, _Yc, _Xc, Xo, Yo ) :-
Wv <- W[Y,X],
Xspc =< Wv,
Hv <- H[Y,X],
Yspc =< Hv,
Ydwn is Yspc - 1,
svg_slide_box( Ydwn, Y, X, Yspc, Xspc, W, H ),
!,
Xo = X, Yo = Y.
svg_bottom_right( Y, X, Yspc, Xspc, Mtx, W, H, Yc, Xc, Xo, Yo ) :-
Xp is X - 1,
( 0 < Xp ->
X1 is Xp,
Y1 is Y
;
X1 is Xc - Xspc,
Y1 is Y - 1,
0 < Y1
),
svg_bottom_right( Y1, X1, Yspc, Xspc, Mtx, W, H, Yc, Xc, Xo, Yo ).
svg_slide_box( 0, _Y, _X, _Yspc, _Xspc, _W, _H ) :- !.
svg_slide_box( I, Y, X, Yspc, Xspc, W, H ) :-
Yi is Y + I,
Wv <- W[Yi,X],
Xspc =< Wv,
Hv <- H[Yi,X],
Yspc =< Hv,
Im is I - 1,
svg_slide_box( Im, Y, X, Yspc, Xspc, W, H ).
svg_cache( false, File, Mtx, Dist, W, H, _Opts ) :-
read_svg_lines( File, Mtx, Dist, W, H ).
svg_cache( true, File, Mtx, Dist, W, H, Opts ) :-
options( postfix_mtx(Msfx), Opts ),
os_postfix( Msfx, File, Mile ),
os_ext( _, pl, Mile, Cile ),
holds( exists_file(Cile), Cexists ),
svg_cache_on( Cexists, Cile, File, Mtx, Dist, W, H ).
svg_cache_on( true, Cile, _File, Mtx, _Dist, W, H ) :-
% fixme:
mtx_from_file( Cile ),
debug_call( svg_legend, read, Cile ),
% fixme: make sure those were created...
Mtx = m, W = w, H = h, % ensures those where as per loaded
% heatmaps( Mtx, H, W ),
true.
svg_cache_on( false, Cile, File, Mtx, Dist, W, H ) :-
read_svg_lines( File, Mtx, Dist, W, H ),
mtx_to_file( [Mtx,W,H], Cile ),
debug_call( svg_legend, wrote, Cile ).
mtx_from_file( File ) :-
tmp:ensure_loaded( File ),
mtx_from_module( tmp ),
abolish( matrix/2 ).
mtx_from_module( Mod ) :-
Mod:matrix(Rtx,X),
Row =.. [Rtx,Arg],
findall( Arg, (call(Mod:Row),length(Arg,X)), Args ),
length( Args, NRows ),
Rtx <- matrix(0, nrow=NRows, ncol=X),
Rtx <- Args,
abolish( Rtx/1 ),
fail.
mtx_from_module( _ ).
mtx_to_file( MtcPrv, File ) :-
en_list( MtcPrv, Mtc ),
maplist( mtx_to_clauses, Mtc, Infos, ClausesNest ),
flatten( ClausesNest, Clauses ),
append( Infos, Clauses, Alauses ),
portray_clauses( Alauses, file(File) ).
% @tbd headers, then move to b_real ?
mtx_to_clauses( Rtx, Info, Clauses ) :-
Mtx <- Rtx,
Mtx = [First|_],
length( First, Len ),
Info = matrix(Rtx,Len),
findall( Row, (member(RRow,Mtx),Row=..[Rtx,RRow]), Clauses ).
read_svg_lines( SvgF, Mtx, Dist, W, H ) :-
open( SvgF, read, In ),
read_line_to_codes( In, Line ),
read_svg_stream( Line, In, Mtx, Dist, W, H ),
close( In ).
read_svg_mtx( end_of_file, _Pfx, _X, _Y, _In, _Mtx ) :- !.
read_svg_mtx( Line, Pfx, Xc, Yc, In, Mtx ) :-
append( Pfx, Rest, Line ),
!,
read_svg_int( XCs, Rest, [0',|Rem] ),
number_codes( X, XCs ),
read_svg_int( YCs, Rem, RemXY ),
number_codes( Y, YCs ),
read_svg_to_space( RemXY, Shift ),
read_svg_int( PCs, Shift, _Leftovers ),
number_codes( P, PCs ),
% mtx_pheatmap( Rws, [cluster_rows='FALSE',cluster_cols='FALSE'] ),
read_svg_mtx_score( Mtx, Xc, Yc, X, P, Y ),
read_line_to_codes( In, NewLine ),
read_svg_mtx( NewLine, Pfx, Xc, Yc, In, Mtx ).
read_svg_mtx( _Line, Pfx, Xc, Yc, In, Mtx ) :-
read_line_to_codes( In, NewLine ),
read_svg_mtx( NewLine, Pfx, Xc, Yc, In, Mtx ).
read_svg_mtx_score( Mtx, _Xc, Yc, X, P, Y ) :-
Max is integer( X + 12 ),
Min is integer( P - 12 ),
% fixme: check Y is negative
MxY is Yc + integer( Y + 36 ),
MnY is Yc + integer(Y),
findall( _, ( between(Min,Max,AnX),
between(MnY,MxY,AnY),
Mtx[AnY,AnX] <- 1
),
_
).
read_svg_to_space -->
[C], { C \== 0' },
!,
read_svg_to_space.
read_svg_to_space --> [_C].
read_svg_stream( Line, In, Mtx, Dist, W, H ) :-
append( `