Newer
Older
# \\\
# Copyright 2021-2022 Louis Héraut*1
#
# *1 INRAE, France
# louis.heraut@inrae.fr
#
# This file is part of ash R toolbox.
#
# ash R toolbox is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# ash R toolbox is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with ash R toolbox. If not, see <https://www.gnu.org/licenses/>.
# ///
#
#
# tools.R
## 1. COLOR MANAGEMENT
### 1.1. Color on colorbar ___________________________________________
# Returns a color of a palette corresponding to a value included
# between the min and the max of the variable
get_color = function (value, min, max, ncolor=256, palette_name='perso', reverse=FALSE) {
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
# If the value is a NA return NA color
if (is.na(value)) {
return (NA)
}
# If the palette chosen is the personal ones
if (palette_name == 'perso') {
colorList = palette_perso
# Else takes the palette corresponding to the name given
} else {
colorList = brewer.pal(11, palette_name)
}
# Gets the number of discrete colors in the palette
nSample = length(colorList)
# Recreates a continuous color palette
palette = colorRampPalette(colorList)(ncolor)
# Separates it in the middle to have a cold and a hot palette
Sample_hot = 1:(as.integer(nSample/2)+1)
Sample_cold = (as.integer(nSample/2)+1):nSample
palette_hot = colorRampPalette(colorList[Sample_hot])(ncolor)
palette_cold = colorRampPalette(colorList[Sample_cold])(ncolor)
# Reverses the palette if it needs to be
if (reverse) {
palette = rev(palette)
palette_hot = rev(palette_hot)
palette_cold = rev(palette_cold)
}
# Computes the absolute max
maxAbs = max(abs(max), abs(min))
# If the value is negative
if (value < 0) {
# Gets the relative position of the value in respect
# to its span
idNorm = (value + maxAbs) / maxAbs
# The index corresponding
id = round(idNorm*(ncolor - 1) + 1, 0)
# The associated color
color = palette_cold[id]
# Same if it is a positive value
} else {
idNorm = value / maxAbs
id = round(idNorm*(ncolor - 1) + 1, 0)
color = palette_hot[id]
}
return(color)
}
### 1.2. Colorbar ____________________________________________________
# Returns the colorbar but also positions, labels and colors of some
# ticks along it
get_palette = function (min, max, ncolor=256, palette_name='perso', reverse=FALSE, nbTick=10) {
# If the palette chosen is the personal ones
if (palette_name == 'perso') {
colorList = palette_perso
# Else takes the palette corresponding to the name given
} else {
colorList = brewer.pal(11, palette_name)
}
# Gets the number of discrete colors in the palette
nSample = length(colorList)
# Recreates a continuous color palette
palette = colorRampPalette(colorList)(ncolor)
# Separates it in the middle to have a cold and a hot palette
Sample_hot = 1:(as.integer(nSample/2)+1)
Sample_cold = (as.integer(nSample/2)+1):nSample
palette_hot = colorRampPalette(colorList[Sample_hot])(ncolor)
palette_cold = colorRampPalette(colorList[Sample_cold])(ncolor)
# Reverses the palette if it needs to be
if (reverse) {
palette = rev(palette)
palette_hot = rev(palette_hot)
palette_cold = rev(palette_cold)
}
# If the min and the max are below zero
if (min < 0 & max < 0) {
# The palette show is only the cold one
paletteShow = palette_cold
# If the min and the max are above zero
} else if (min > 0 & max > 0) {
# The palette show is only the hot one
paletteShow = palette_hot
# Else it is the entire palette that is shown
} else {
paletteShow = palette
}
# The position of ticks is between 0 and 1
posTick = seq(0, 1, length.out=nbTick)
# Blank vector to store corresponding labels and colors
labTick = c()
colTick = c()
# For each tick
for (i in 1:nbTick) {
# Computes the graduation between the min and max
lab = (i-1)/(nbTick-1) * (max - min) + min
# Gets the associated color
col = get_color(lab, min=min, max=max,
ncolor=ncolor,
palette_name=palette_name,
reverse=reverse)
# Stores them
labTick = c(labTick, lab)
colTick = c(colTick, col)
}
# List of results
res = list(palette=paletteShow, posTick=posTick,
labTick=labTick, colTick=colTick)
return(res)
}
### 1.3. Palette tester ______________________________________________
# Allows to display the current personal palette
palette_tester = function (palette_name='perso', n=256) {
# If the palette chosen is the personal ones
if (palette_name == 'perso') {
colorList = palette_perso
# Else takes the palette corresponding to the name given
} else {
colorList = brewer.pal(11, palette_name)
}
# An arbitrary x vector
X = 1:n
# All the same arbitrary y position to create a colorbar
Y = rep(0, times=n)
# Recreates a continuous color palette
palette = colorRampPalette(palette_perso)(n)
# Open a plot
p = ggplot() +
# Make the theme blank
theme(
plot.background = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.border = element_blank(),
panel.background = element_blank(),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
axis.text.x = element_blank(),
axis.text.y = element_blank(),
axis.ticks = element_blank(),
axis.line = element_blank()
) +
# Plot the palette
geom_line(aes(x=X, y=Y), color=palette[X], size=60) +
scale_y_continuous(expand=c(0, 0))
# Saves the plot
ggsave(plot=p,
filename=paste('palette_test', '.pdf', sep=''),
width=10, height=10, units='cm', dpi=100)
}
## 2. PERSONAL PLOT __________________________________________________
### 2.1. Circle ______________________________________________________
# Allow to draw circle in ggplot2 with a radius and a center position
gg_circle = function(r, xc, yc, color="black", fill=NA, ...) {
x = xc + r*cos(seq(0, pi, length.out=100))
ymax = yc + r*sin(seq(0, pi, length.out=100))
ymin = yc + r*sin(seq(0, -pi, length.out=100))
annotate("ribbon", x=x, ymin=ymin, ymax=ymax, color=color,
fill=fill, ...)
}
## 3. NUMBER MANAGEMENT ______________________________________________
### 3.1. Number formatting ___________________________________________
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
# Returns the power of ten of the scientific expression of a value
get_power = function (value) {
# Do not care about the sign
value = abs(value)
# If the value is greater than one
if (value >= 1) {
# The magnitude is the number of character of integer part
# of the value minus one
power = nchar(as.character(as.integer(value))) - 1
# If value is zero
} else if (value == 0) {
# The power is zero
power = 0
# If the value is less than one
} else {
# Extract the decimal part
dec = gsub('0.', '', as.character(value), fixed=TRUE)
# Number of decimal with zero
ndec = nchar(dec)
# Number of decimal without zero
nnum = nchar(as.character(as.numeric(dec)))
# Compute the power of ten associated
power = -(ndec - nnum + 1)
}
return(power)
}
### 3.2. Pourcentage of variable _____________________________________
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
# Returns the value corresponding of a certain percentage of a
# data serie
gpct = function (pct, L, min_lim=NULL, shift=FALSE) {
# If no reference for the serie is given
if (is.null(min_lim)) {
# The minimum of the serie is computed
minL = min(L, na.rm=TRUE)
# If a reference is specified
} else {
# The reference is the minimum
minL = min_lim
}
# Gets the max
maxL = max(L, na.rm=TRUE)
# And the span
spanL = maxL - minL
# Computes the value corresponding to the percentage
xL = pct/100 * as.numeric(spanL)
# If the value needs to be shift by its reference
if (shift) {
xL = xL + minL
}
return (xL)
}
### 3.3. Add months __________________________________________________