-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsubheatmap_utils.jl
More file actions
150 lines (142 loc) · 6.57 KB
/
Copy pathsubheatmap_utils.jl
File metadata and controls
150 lines (142 loc) · 6.57 KB
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
module SubheatmapUtils
using DataFrames
using VegaLite
fixlabel(::Missing) = missing
fixlabel(s::AbstractString) = replace(s, r"</?[^>]+>" => "")
multilinetovector(::Missing) = missing
multilinetovector(s::AbstractString) =
split(replace(s, r"<br>\n?|\n" => "\n"), '\n')
function subheatmap_frame(z::AbstractMatrix,
row_axis::AbstractDataFrame,
colXsub_axis::AbstractDataFrame;
row_label_col::Symbol = :axis_label,
col_label_col::Symbol = :axis_label,
col_sub_cols::AbstractVector{Symbol},
col_cols = Not(col_sub_cols),
extra_row_cols::Union{AbstractVector{Symbol}, Nothing} = nothing,
extra_col_cols::Union{AbstractVector{Symbol}, Nothing} = nothing,
tips::Union{AbstractMatrix,Nothing} = nothing)
@assert nrow(row_axis) == size(z, 1)
@assert nrow(colXsub_axis) == size(z, 2)
row_axis = copy(row_axis)
row_axis[!, row_label_col] = fixlabel.(row_axis[!, row_label_col])
#row_axis[!, row_label_col] = multilinetovector.(row_axis[!, row_label_col])
col_axis = select(colXsub_axis, col_cols) |> unique!
col_axis.col_index = 1:nrow(col_axis)
colXsub_axis = copy(colXsub_axis, copycols=false)
colXsub_axis.orig_order = 1:nrow(colXsub_axis)
colXsub_axis = innerjoin(colXsub_axis, col_axis, on=names(col_axis)[1:end-1])
sort!(colXsub_axis, :orig_order)
subkey_col = col_sub_cols[1]
# HACK for unique(CatArray) returning Array{String}
subkeys = sort!(unique!(select(colXsub_axis, [subkey_col]))[!, subkey_col])
@show subkeys
if colXsub_axis[!, subkey_col] isa CategoricalArray
# HACK subkeys and subkey_col have different pools now
colXsub_axis.sub_index = searchsortedfirst.(Ref(CategoricalArrays.refs(subkeys)),
CategoricalArrays.refs(colXsub_axis[!, subkey_col]))
else
colXsub_axis.sub_index = searchsortedfirst.(Ref(subkeys), colXsub_axis[!, subkey_col])
end
@assert nrow(colXsub_axis) <= length(subkeys)*nrow(col_axis) # check that col_axis + subkey are really a key for colXsub_axis
#col_axis[!, col_label_col] = multilinetovector.(col_axis[!, col_label_col])
col_axis[!, col_label_col] = fixlabel.(col_axis[!, col_label_col])
res = DataFrame(value = copy(vec(z)),
row_index = repeat(1:nrow(row_axis), outer=size(z, 2)),
col_index = repeat(colXsub_axis.col_index, inner=size(z, 1)),
sub_index = repeat(colXsub_axis.sub_index, inner=size(z, 1)))
res.row_label = row_axis[res.row_index, row_label_col]
res.col_label = col_axis[res.col_index, col_label_col]
res.sub_label = subkeys[res.sub_index]
if !isnothing(tips)
@assert size(tips) == size(z)
res.tooltip = multilinetovector.(vec(tips))
end
if !isnothing(extra_row_cols)
for col in extra_row_cols
res[!, "row_$col"] = repeat(row_axis[!, col], outer=size(z, 2))
end
end
if !isnothing(extra_col_cols)
for col in extra_col_cols
res[!, "col_$col"] = repeat(colXsub_axis[!, col], inner=size(z, 1))
end
end
return res, row_axis, col_axis
end
function DiagonalTriangles(; scale::Number=1, offset::Number=0.1)
hm = (1-offset)*scale
vm = scale
l = (2-offset)*scale
return ["M$(-hm) $(vm)v$(-l)h$(l)z", "M$(-hm) $(vm)h$(l)v$(-l)z"]
end
const HotColorScheme = ["rgb(0,0,0)", "rgb(230,0,0)", "rgb(255,210,0)", "rgb(255,255,255)"]
function vegalite_subheatmap(subheatmap_df::AbstractDataFrame;
cell_width=20, cell_height=20, gap_width=1, grid_width=0.25,
labelLimit_l=200, labelLimit_b=200,
subshapes::AbstractArray=DiagonalTriangles(),
value_domain=(-10, 0), colorscheme=HotColorScheme,
xaxis_label::AbstractString = "column",
xaxis_tick_col=:axis_label,
yaxis_label::AbstractString = "row",
yaxis_tick_col=:axis_label,
subaxis_label::AbstractString = "sub",
coloraxis_label::AbstractString = "value"
)
subheatmap_plot = subheatmap_df |> @vlplot(
config={view={stroke=nothing}},
height={step=cell_height+gap_width},
width={step=cell_width+gap_width},
mark={:point, filled=true},
row={"rowblock_index:n"}, column={"colblock_index:n"},
x={"col_label:n",
sort=:col_index,
axis = {
title=xaxis_label,
tickBand = "extent",
grid = true,
gridWidth = grid_width,
labelLimit = labelLimit_b,
labelExpr = "split(replace(datum.label, /<br>[\\n]?|[\\n]/, '\\n'), '\\n')",
labelAlign = "left", labelBaseline = "middle", labelAngle = 45,
},
#scale = {domain = cols_df[!, xaxis_tick_col]}
},
y={"row_label:n",
sort=:row_index,
axis = {
labelLimit = labelLimit_l,
labelExpr = "split(replace(datum.label, /<br>[\\n]?|[\\n]/, '\\n'), '\\n')",
labelOffset = "(1-length(split(replace(datum.label, /<br>[\\n]?|[\\n]/, '\\n'), '\\n')))*5",
title = yaxis_label,
titleX = -labelLimit_l-5,
tickBand = "extent",
grid = true,
gridWidth = grid_width,
},
#scale = {domain = rows_df[!, yaxis_tick_col]}
},
shape={
"sub_label:n", header={title=subaxis_label},
sort={field="sub_index", order="descending"},
scale={range=subshapes}, #domain=sublabels,
},
color={
"value:q",
scale={domain=value_domain, scheme=colorscheme, interpolate=:rgb},
legend={title=coloraxis_label, titleOrient="right"},
},
tooltip={
"tooltip:n"
},
resolve={scale={x="independent"}},
opacity={ value=1 },
size={ value=400 }
)
# HACK remove properties that are not present in the data
hasproperty(subheatmap_df, :rowblock_index) || delete!(subheatmap_plot.encoding.params, "row")
hasproperty(subheatmap_df, :collock_index) || delete!(subheatmap_plot.encoding.params, "column")
hasproperty(subheatmap_df, :tooltip) || delete!(subheatmap_plot.encoding.params, "tooltip")
return subheatmap_plot
end
end