diff --git a/src/raster/r.boxplot/r.boxplot.html b/src/raster/r.boxplot/r.boxplot.html index d39142e7be..458b46bcfc 100644 --- a/src/raster/r.boxplot/r.boxplot.html +++ b/src/raster/r.boxplot/r.boxplot.html @@ -27,9 +27,11 @@

DESCRIPTION

There are a few layout options, including the option to rotate -the plot and the x-axis labels, print the boxplot(s) with notches and -sort the boxplot from low to high (ascending) or from high to low (descending) -median. +the plot and the x-axis labels, print the boxplot(s) with notches, sort the +boxplot from low to high (ascending) or from high to low (descending) median, +and color the boxplots according to the corresponding categories of the zonal +raster. +

NOTE

To include outliers, the function converts the raster cell with outlier @@ -50,7 +52,7 @@

Example 1

g.region raster=elevation r.boxplot -h input=elevation plot_dimensions="7,1" output="r_boxplot_01.png" - +


@@ -64,7 +66,7 @@

Example 2

 r.boxplot -r input=elevation zone=landclass96 output="r_boxplot_02.png" 
 
-
+


@@ -80,11 +82,10 @@

Example 3

 r.boxplot -o order=ascending input=elevation zones=landclass96 output="r_boxplot_03.png" map_outliers="outliers"
 
-
+


-Figure 3: Boxplot of elevation raster layer per land use zone, including outliers.

Below, part of the landclass96 raster map is shown, with on top the vector point @@ -94,6 +95,22 @@

Example 3


+

Example 4

+Draw boxplots of the values of the elevation layer per category from +the landclass96 layer from the same +NC sample +dataset. Set the -c flag to color the boxplots, use order=ascending +to order the boxplots from low to high median, and set the fontsize to 11. + +
+r.boxplot -c order=ascending fontsize=11 input=elevation zones=landclass96 output="r_boxplot_04.png"
+
+

+ +

+
+ +

Acknowledgements

This work was carried in the framework of the Save the tiger, save the grassland, save the water project by the @@ -112,3 +129,4 @@

AUTHOR

Paulo van Breugel
Applied Geo-information Sciences
HAS University of Applied Sciences
+ diff --git a/src/raster/r.boxplot/r.boxplot.py b/src/raster/r.boxplot/r.boxplot.py index 3548b8d258..c0de0f3076 100644 --- a/src/raster/r.boxplot/r.boxplot.py +++ b/src/raster/r.boxplot/r.boxplot.py @@ -1,4 +1,5 @@ #!/usr/bin/env python + ############################################################################ # # MODULE: r.boxplot @@ -73,6 +74,15 @@ # % required: no # %end +# %option +# % key: fontsize +# % type: integer +# % label: Font size +# % description: Default font size +# % guisection: Plot options +# % required: no +# %end + # %flag # % key: h # % label: horizontal boxplot(s) @@ -119,10 +129,22 @@ # % guisection: Plot options # %end +# %flag +# % key: c +# % label: Color boxploxs +# % description: Color boxploxs using the colors of the categories of the zonal raster +# % guisection: Plot options +# %end + # %rules # % requires: map_outliers, -o # %end +# %rules +# % requires: -c, zones +# %end + + import sys import atexit import uuid @@ -210,6 +232,7 @@ def bxp_nozones( rotate_label, name_outliers_map, whisker_range, + fontsize, ): """Compute the statistics used to create the boxplot, and create the boxplot. This function is used in case @@ -314,7 +337,7 @@ def bxp_nozones( else: fliers = [] - # Set plot dimensions + # Set plot dimensions and fontsize if dimensions: dimensions = [float(x) for x in dimensions.split(",")] else: @@ -322,6 +345,8 @@ def bxp_nozones( dimensions = [4, 8] else: dimensions = [8, 4] + if fontsize: + plt.rcParams["font.size"] = fontsize # Create plot _, ax = plt.subplots(figsize=dimensions) @@ -369,6 +394,8 @@ def bxp_zones( sort, name_outliers_map, whisker_range, + bpcolors, + fontsize, ): """Compute the statistics used to create the boxplot, and create the boxplots per zone from the zonal map.""" @@ -393,6 +420,27 @@ def bxp_zones( labels = [_f for _f in labels if _f] labels = [_y[1] for _y in [_x.split("|") for _x in labels]] + # Get colors + if bpcolors: + zones_color = Module("r.colors.out", map=zones, stdout_=PIPE).outputs.stdout + zones_color = zones_color.replace("\r", "").split("\n") + zones_color = [_f for _f in zones_color if _f] + zones_color = [ + _x + for _x in zones_color + if not _x.startswith("nv") and not _x.startswith("default") + ] + zones_color = [_y[1] for _y in [_x.split(" ") for _x in zones_color]] + zones_color = [_z.split(":") for _z in zones_color] + zones_rgb = [[int(_x) / 255 for _x in _y] for _y in zones_color] + txt_rgb = [] + for i in zones_color: + rgb_i = list(map(int, i)) + if rgb_i[0] * 0.299 + rgb_i[1] * 0.587 + rgb_i[2] * 0.114 > 149: + txt_rgb.append([0, 0, 0, 0.7]) + else: + txt_rgb.append([1, 1, 1, 0.7]) + # Compute statistics quantstats = Module( "r.stats.quantile", @@ -418,6 +466,9 @@ def bxp_zones( ordered_list = [i for _, i in sorted(zip(medians, ids), reverse=False)] else: ordered_list = list(range(0, len(order_bpl))) + if bpcolors: + zones_rgb[:] = [zones_rgb[i] for i in ordered_list] + txt_rgb[:] = [txt_rgb[i] for i in ordered_list] # Define the boxes boxes = [] @@ -551,7 +602,7 @@ def bxp_zones( elif name_outliers_map: gs.message("\n--> There are no outliers") - # Set plot dimensions + # Set plot dimensions and fontsize if dimensions: dimensions = [float(x) for x in dimensions.split(",")] else: @@ -559,10 +610,24 @@ def bxp_zones( dimensions = [8, 4] else: dimensions = [4, 8] + if fontsize: + plt.rcParams["font.size"] = fontsize # Plot the figure _, ax = plt.subplots(figsize=dimensions) - ax.bxp(boxes, showfliers=True, widths=0.6, vert=vertical, shownotches=notch) + bxplot = ax.bxp( + boxes, + showfliers=True, + widths=0.6, + vert=vertical, + shownotches=notch, + patch_artist=bpcolors, + ) + if bpcolors: + for patch, color in zip(bxplot["boxes"], zones_rgb): + patch.set_facecolor(color) + for median, mcolor in zip(bxplot["medians"], txt_rgb): + median.set_color(mcolor) if vertical: ax.set_ylabel(strip_mapset(name)) else: @@ -589,7 +654,13 @@ def main(options, flags): if zones_raster: check_integer(zones_raster) output = options["output"] + fontsize = options["fontsize"] + if fontsize: + int(fontsize) + else: + fontsize = 10 whisker_range = float(options["range"]) + bpcolor = flags["c"] if whisker_range <= 0: gs.fatal(_("The range value need to be larger than 0")) if flags["h"]: @@ -622,6 +693,8 @@ def main(options, flags): sort=sort, name_outliers_map=name_outliers_map, whisker_range=whisker_range, + bpcolors=bpcolor, + fontsize=fontsize, ) else: bxp_nozones( @@ -635,6 +708,7 @@ def main(options, flags): rotate_label=rotate_label, name_outliers_map=name_outliers_map, whisker_range=whisker_range, + fontsize=fontsize, ) diff --git a/src/raster/r.boxplot/r_boxplot_04.png b/src/raster/r.boxplot/r_boxplot_04.png new file mode 100644 index 0000000000..4730863878 Binary files /dev/null and b/src/raster/r.boxplot/r_boxplot_04.png differ