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/>.
# ///
#
#
# plotting/matrix.R
#
#
# Generates a summarizing matrix of the trend analyses of all station for different hydrological variables and periods. Also shows difference of means between specific periods.
matrix_panel = function (list_df2plot, df_meta, trend_period, mean_period, slice=NULL, outdirTmp='', outnameTmp='matrix', title=NULL, A3=FALSE) {
nbp = length(list_df2plot)
# Get all different stations code
Code = levels(factor(df_meta$code))
nCode = length(Code)
df_trend = list_df2plot[[1]]$trend
# Convert 'trend_period' to list
trend_period = as.list(trend_period)
# Number of trend period
nPeriod_trend = length(trend_period)
# Fix the maximal number of period to the minimal possible
# Extract start and end of trend periods
Start = df_trend_code$period_start
# Get the name of the different period
UStart = levels(factor(Start))
# Compute the max of different start and end
# so the number of different period
# If the number of period for the trend is greater
# than the current max period, stocks it
if (nPeriod > nPeriod_max) {
nPeriod_max = nPeriod
}
}
Start_code = vector(mode='list', length=nCode)
End_code = vector(mode='list', length=nCode)
Code_code = vector(mode='list', length=nCode)
Periods_code = vector(mode='list', length=nCode)
Start = df_trend_code$period_start
End = df_trend_code$period_end
# Get the name of the different period
UStart = levels(factor(Start))
# Compute the max of different start and end
# so the number of different period
nPeriod = max(length(UStart), length(UEnd))
# Vector to store trend period
Periods = append(Periods,
paste(Start[i],
End[i],
sep=' / '))
}
Start_code[[j]] = Start
End_code[[j]] = End
Code_code[[j]] = code
Periods_code[[j]] = Periods
}
# Blank array to store mean of the trend for each
# station, perdiod and variable
TrendMean_code = array(rep(1, nPeriod_trend*nbp*nCode),
dim=c(nPeriod_trend, nbp, nCode))
# Extracts the data corresponding to the
# current variable
# Extracts the trend corresponding to the
# current variable
df_trend = list_df2plot[[i]]$trend
p_threshold = list_df2plot[[i]]$p_threshold
# Extracts the data corresponding to the code
df_data_code = df_data[df_data$code == code,]
# Extracts the trend corresponding to the code
Start = Start_code[Code_code == code][[1]][j]
End = End_code[Code_code == code][[1]][j]
Periods = Periods_code[Code_code == code][[1]][j]
df_data_code_per =
df_data_code[df_data_code$Date >= Start
& df_data_code$Date <= End,]
df_trend_code_per =
df_trend_code[df_trend_code$period_start == Start
& df_trend_code$period_end == End,]
# If there is more than one trend on the same period
# Normalises the trend value by the mean of the data
# Computes the min and the max of the mean trend for
# all the station
minTrendMean = apply(TrendMean_code, c(1, 2), min, na.rm=TRUE)
maxTrendMean = apply(TrendMean_code, c(1, 2), max, na.rm=TRUE)
Periods_trend = c()
NPeriod_trend = c()
Type_trend = list()
Code_trend = c()
Pthresold_trend = c()
TrendMean_trend = c()
DataMean_trend = c()
Fill_trend = c()
Color_trend = c()
# Extracts the data corresponding to the current variable
# Extracts the trend corresponding to the
# current variable
df_trend = list_df2plot[[i]]$trend
p_threshold = list_df2plot[[i]]$p_threshold
# Extracts the data corresponding to the code
df_data_code = df_data[df_data$code == code,]
# Extracts the trend corresponding to the code
Start = Start_code[Code_code == code][[1]][j]
End = End_code[Code_code == code][[1]][j]
Periods = Periods_code[Code_code == code][[1]][j]
df_data_code_per =
df_data_code[df_data_code$Date >= Start
& df_data_code$Date <= End,]
df_trend_code_per =
df_trend_code[df_trend_code$period_start == Start
& df_trend_code$period_end == End,]
# If there is more than one trend on the same period
# Normalises the trend value by the mean of the data
color_res = get_color(trendMean,
minTrendMean[j, i],
maxTrendMean[j, i],
palette_name='perso',
reverse=TRUE)
# Specifies the color fill and contour of
# table cells
fill = color_res
color = 'white'
Pthresold = p_thresold
} else {
fill = 'white'
color = 'grey85'
Pthresold = NA
}
Periods_trend = append(Periods_trend, Periods)
NPeriod_trend = append(NPeriod_trend, j)
Type_trend = append(Type_trend, type)
Code_trend = append(Code_trend, code)
Pthresold_trend = append(Pthresold_trend, Pthresold)
TrendMean_trend = append(TrendMean_trend, trendMean)
DataMean_trend = append(DataMean_trend, dataMean)
Fill_trend = append(Fill_trend, fill)
Color_trend = append(Color_trend, color)
}
}
}
# If there is a 'mean_period'
if (!is.null(mean_period)) {
Periods_mean = c()
NPeriod_mean = c()
Type_mean = list()
Code_mean = c()
DataMean_mean = c()
BreakMean_mean = c()
# Convert 'mean_period' to list
mean_period = as.list(mean_period)
# Number of mean period
nPeriod_mean = length(mean_period)
# Blank array to store difference of mean between two periods
BreakMean_code = array(rep(1, nPeriod_mean*nbp*nCode),
dim=c(nPeriod_mean, nbp, nCode))
# Blank array to store mean for a temporary period in order
# to compute the difference of mean with a second period
dataMeantmp = array(rep(NA, nbp*nCode),
dim=c(nbp, nCode))
# For all mean period
for (j in 1:nPeriod_mean) {
# Extracts the data corresponding to
# the current variable
df_data_code = df_data[df_data$code == code,]
# Get the current start and end of the sub period
Start_mean = mean_period[[j]][1]
End_mean = mean_period[[j]][2]
# Extract the data corresponding to this sub period
df_data_code_per =
df_data_code[df_data_code$Date >= Start_mean
& df_data_code$Date <= End_mean,]
Datemin = min(df_data_code_per$Date)
Datemax = max(df_data_code_per$Date)
Periods = paste(Datemin, Datemax,
sep=' / ')
# Mean of the flow over the sub period
dataMean = mean(df_data_code_per$Qm3s,
na.rm=TRUE)
# Normalises the break by the mean of the
# initial period
# Stores temporarily the mean of the current period
Periods_mean = append(Periods_mean, Periods)
NPeriod_mean = append(NPeriod_mean, j)
Type_mean = append(Type_mean, type)
Code_mean = append(Code_mean, code)
DataMean_mean = append(DataMean_mean, dataMean)
BreakMean_mean = append(BreakMean_mean,
BreakMean)
}
}
}
# Computes the min and the max of the mean trend for
# all the station
minBreakMean = apply(BreakMean_code, c(1, 2),
min, na.rm=TRUE)
maxBreakMean = apply(BreakMean_code, c(1, 2),
max, na.rm=TRUE)
color_res = get_color(BreakMean,
minBreakMean[j, i],
maxBreakMean[j, i],
palette_name='perso',
reverse=TRUE)
Fill_mean = append(Fill_mean, fill)
Color_mean = append(Color_mean, color)
# If the slice option is not specified, the info for all
# stations will be draw on the same page
# Extracts each possibilities of first letter of station code
print(paste('Matrix for region :', fL))
# Get only station code with the same first letter
subCodefL = Code[substr(Code, 1, 1) == fL]
# Computes the number of pages needed to plot all stations
# Creates logical vector to select only info about
# stations that will be plot on the page
subPeriods_trend = Periods_trend[CodefL_trend]
subNPeriod_trend = NPeriod_trend[CodefL_trend]
subType_trend = Type_trend[CodefL_trend]
subCode_trend = Code_trend[CodefL_trend]
subPthresold_trend = Pthresold_trend[CodefL_trend]
subTrendMean_trend = TrendMean_trend[CodefL_trend]
subDataMean_trend = DataMean_trend[CodefL_trend]
subFill_trend = Fill_trend[CodefL_trend]
subColor_trend = Color_trend[CodefL_trend]
subPeriods_mean = Periods_mean[CodefL_mean]
subNPeriod_mean = NPeriod_mean[CodefL_mean]
subType_mean = Type_mean[CodefL_mean]
subCode_mean = Code_mean[CodefL_mean]
subDataMean_mean = DataMean_mean[CodefL_mean]
subBreakMean_mean = BreakMean_mean[CodefL_mean]
subFill_mean = Fill_mean[CodefL_mean]
subColor_mean = Color_mean[CodefL_mean]
# Extracts the name of the currently hydrological
# region plotted
title = df_meta[df_meta$code == subCode[1],]$region_hydro
# Fixes the height and width of the table according to
# the number of station and the number of column to draw
height = nsubCode
width = nbp * 2 * nPeriod_trend + nPeriod_trend + nPeriod_mean * nbp + nPeriod_mean + nbp
# Fixes the size of the plot area to keep proportion right
theme(
panel.border=element_blank(),
axis.text.x=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank(),
axis.ticks.x=element_blank(),
axis.title.y=element_blank(),
plot.margin=margin(t=5, r=5, b=5, l=5, unit="mm")
)
xt = 1 - 6
yt = height + 2
Title = bquote(bold(.(title)))
mat = mat +
annotate("text", x=xt, y=yt,
label=Title,
hjust=0, vjust=1,
size=6, color="#00A3A8")
### Trend ###
# Extracts the info to plot associated to the
# right period
Type_trend_per =
subType_trend[subNPeriod_trend == j]
Code_trend_per =
subCode_trend[subNPeriod_trend == j]
Pthresold_trend_per =
subPthresold_trend[subNPeriod_trend == j]
TrendMean_trend_per =
subTrendMean_trend[subNPeriod_trend == j]
DataMean_trend_per =
subDataMean_trend[subNPeriod_trend == j]
Fill_trend_per =
subFill_trend[subNPeriod_trend == j]
Color_trend_per =
subColor_trend[subNPeriod_trend == j]
# Converts the vector of hydrological variable to
# a vector of integer associated to those variable
Xtmp = as.integer(factor(as.character(Type_trend_per)))
# Computes X position of the column of the period dates
Xc = j + (j - 1)*nbp*2
# Computes X positions of columns of the mean of
# variables
# Computes X positions of columns of the mean trend
# Computes Y positions of each line for each station
x = Xc - 0.4
xend = X[length(X)] + 0.25
y = height + 1
yend = height + 1
mat = mat +
annotate("segment",
x=x, xend=xend,
y=y, yend=yend,
color="grey40", size=0.35)
yt = y + 0.15
Start = trend_period[[j]][1]
End = trend_period[[j]][2]
periodName = bquote(bold('Période')~bold(.(as.character(j))))
mat = mat +
annotate("text", x=x, y=yt,
label=periodName,
hjust=0, vjust=0.5,
size=3, color='grey40')
gg_circle(r=0.45, xc=X[i], yc=Y[i],
fill=Fill_trend_per[i],
color=Color_trend_per[i]) +
gg_circle(r=0.45, xc=Xm[i], yc=Y[i],
fill='white', color='grey40') +
gg_circle(r=0.45, xc=Xc, yc=Y[i],
fill='white', color='grey40')
}
# Converts it to the right format with two
# significant figures
trendMeanC = signif(trendMean*100, 2)
# Same for the mean of a variable over
# the current period
dataMean = DataMean_trend_per[i]
dataMeanC = signif(dataMean, 2)
hjust=0.5, vjust=0.5,
size=3, color='grey40')
}
mat = mat +
annotate('text', x=Xc, y=max(Y) + 0.85,
label=bquote(bold('Début')),
hjust=0.5, vjust=0.5,
size=3, color='grey20') +
annotate('text', x=Xc, y=max(Y) + 0.6,
label=bquote(bold('Fin')),
hjust=0.5, vjust=0.5,
size=3, color='grey20')
annotate('text', x=X[i], y=max(Y) + 0.82,
label=bquote(.(type)),
hjust=0.5, vjust=0.5,
size=3.25, color='grey20') +
annotate('text', x=X[i], y=max(Y) + 0.6,
label=bquote('[%.'*ans^{-1}*']'),
hjust=0.5, vjust=0.5,
size=2, color='grey40') +
annotate('text', x=Xm[i], y=max(Y) + 0.82,
label=bquote('µ'*.(type)),
hjust=0.5, vjust=0.5,
size=3.25, color='grey20') +
annotate('text', x=Xm[i], y=max(Y) + 0.6,
label=bquote('['*m^3*'.'*s^{-1}*']'),
hjust=0.5, vjust=0.5,
size=2, color='grey40')
}
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
code = subCode[k]
label = Periods_trend[subNPeriod_trend == j
& subCode_trend == code][1]
periodStart = substr(label, 1, 4)
periodEnd = substr(label, 14, 17)
mat = mat +
annotate('text', x=Xc, y=k + 0.13,
label=bquote(bold(.(periodStart))),
hjust=0.5, vjust=0.5,
size=3, color='grey40') +
annotate('text', x=Xc, y=k - 0.13,
label=bquote(bold(.(periodEnd))),
hjust=0.5, vjust=0.5,
size=3, color='grey40')
}
}
### Mean ###
for (j in 1:nPeriod_mean) {
Type_mean_per =
subType_mean[subNPeriod_mean == j]
Code_mean_per =
subCode_mean[subNPeriod_mean == j]
DataMean_mean_per =
subDataMean_mean[subNPeriod_mean == j]
BreakMean_mean_per =
subBreakMean_mean[subNPeriod_mean == j]
Fill_mean_per =
subFill_mean[subNPeriod_mean == j]
Color_mean_per =
subColor_mean[subNPeriod_mean == j]
Xtmp_mean = as.integer(factor(as.character(Type_mean_per)))
Xc_mean = j + (j - 1)*nbp + X[length(X)]
Xm_mean = Xtmp_mean + (j - 1)*nbp + j + X[length(X)]
Xr_mean = Xtmp_mean + (j - 1)*nbp*2 + j + X[length(X)]
Y_mean = as.integer(factor(Code_mean_per))
x = Xc_mean - 0.4
xend = Xm_mean[length(Xm_mean)] + 0.25
y = height + 1
yend = height + 1
mat = mat +
annotate("segment",
x=x, xend=xend,
y=y, yend=yend,
color="grey40", size=0.35)
yt = y + 0.15
Start = mean_period[[j]][1]
End = mean_period[[j]][2]
periodName = bquote(bold('Période')~bold(.(as.character(j+nPeriod_trend))))
mat = mat +
annotate("text", x=x, y=yt,
label=periodName,
hjust=0, vjust=0.5,
size=3, color='grey40')
if (j > 1) {
x = Xr_mean[1] - 0.4
xend = Xr_mean[length(Xr_mean)] + 0.25
mat = mat +
annotate("segment",
x=x, xend=xend,
y=y, yend=yend,
color="grey40", size=0.35)
breakName = bquote(bold('Écart')~bold(.(as.character(j-1+nPeriod_trend)))*bold('-')*bold(.(as.character(j+nPeriod_trend))))
mat = mat +
annotate("text", x=x, y=yt,
label=breakName,
hjust=0, vjust=0.5,
size=3, color='grey40')
}
for (i in 1:length(Xm_mean)) {
mat = mat +
gg_circle(r=0.45, xc=Xm_mean[i], yc=Y[i],
fill='white', color='grey40') +
gg_circle(r=0.45, xc=Xc_mean, yc=Y[i],
fill='white', color='grey40')
if (j > 1) {
mat = mat +
gg_circle(r=0.45, xc=Xr_mean[i], yc=Y[i],
fill=Fill_mean_per[i],
color=Color_mean_per[i])
}
}
for (i in 1:length(DataMean_mean_per)) {
dataMean = signif(DataMean_mean_per[i], 2)
mat = mat +
annotate('text', x=Xm_mean[i], y=Y[i],
label=dataMean,
hjust=0.5, vjust=0.5,
size=3, color='grey40')
if (j > 1) {
BreakMean = BreakMean_mean_per[i]
BreakC = signif(BreakMean*100, 2)
mat = mat +
annotate('text', x=Xr_mean[i], y=Y[i],
label=BreakC,
hjust=0.5, vjust=0.5,
size=3, color='white')
}
}
mat = mat +
annotate('text', x=Xc_mean, y=max(Y) + 0.85,
label=bquote(bold('Début')),
hjust=0.5, vjust=0.5,
size=3, color='grey20') +
annotate('text', x=Xc_mean, y=max(Y) + 0.6,
label=bquote(bold('Fin')),
hjust=0.5, vjust=0.5,
size=3, color='grey20')
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
type = list_df2plot[[i]]$type
mat = mat +
annotate('text', x=Xm_mean[i], y=max(Y) + 0.82,
label=bquote('µ'*.(type)),
hjust=0.5, vjust=0.5,
size=3.25, color='grey20') +
annotate('text', x=Xm_mean[i], y=max(Y) + 0.6,
label=bquote('['*m^3*'.'*s^{-1}*']'),
hjust=0.5, vjust=0.5,
size=2, color='grey40')
if (j > 1) {
mat = mat +
annotate('text', x=Xr_mean[i], y=max(Y) + 0.82,
label=bquote('d'*.(type)),
hjust=0.5, vjust=0.5,
size=3.25, color='grey20') +
annotate('text', x=Xr_mean[i], y=max(Y) + 0.6,
label=bquote('[%]'),
hjust=0.5, vjust=0.5,
size=2, color='grey40')
}
}
for (k in 1:nsubCode) {
code = subCode[k]
label = Periods_mean[subNPeriod_mean == j
& subCode_mean == code][1]
periodStart = substr(label, 1, 4)
periodEnd = substr(label, 14, 17)
mat = mat +
annotate('text', x=Xc_mean, y=k + 0.13,
label=bquote(bold(.(periodStart))),
hjust=0.5, vjust=0.5,
size=3, color='grey40') +
annotate('text', x=Xc_mean, y=k - 0.13,
label=bquote(bold(.(periodEnd))),
hjust=0.5, vjust=0.5,
size=3, color='grey40')
}
}
### Code ###
for (k in 1:nsubCode) {
code = subCode[k]
name = df_meta[df_meta$code == code,]$nom
ncharMax = 38
if (nchar(name) > ncharMax) {
name = paste(substr(name, 1, ncharMax), '...', sep='')
}
mat = mat +
annotate('text', x=0.3, y=k + 0.14,
label=bquote(bold(.(code))),
hjust=1, vjust=0.5,
size=3.5, color="#00A3A8") +
annotate('text', x=0.3, y=k - 0.14,
label=name,
hjust=1, vjust=0.5,
size=3.5, color="#00A3A8")
}
### Environment ###
mat = mat +
coord_fixed() +
scale_x_continuous(limits=c(1 - rel(6),
width + rel(0.5)),
expand=c(0, 0)) +
scale_y_continuous(limits=c(1 - rel(0.5),
height + rel(2)),
expand=c(0, 0))
# Saving matrix plot
if (A3) {
width = 42
height = 29.7
dpi = 300
} else {
width = 29.7
height = 21
dpi = 100
}
ggsave(plot=mat,
path=outdirTmp,
filename=paste(outnameTmp, '_', fL, imat, '.pdf',
sep=''),