# How to Draw Rectangle Chart Using Three Layers of Data?

I have some data given at three levels:

ClearAll[level1, level2, level3, labLevel1, labLevel2,
labLevel3];
level1 = {38.63, 16.17};
level2 = {{19.75, 9.26, 9.61}, {2, 6.07, 8.10}};
level3 = {{{5.88, 5.02, 5.56, 3.3}, {4.05, 2.21, 3}, {4.5, 4.91, 0.2}}, {{1, 1},{2.77, 3.3},{2.07, 1.5, 3.11, 1.43}}};

For labels across 3 levels:

labLevel1 = {"Distortions induced by State",
"Barriers to domestic/foreign entry"};

labLevel2 = {{"Public ownership", "Involvelment in business operations", "Simplification/evaluation of regulations"}, {"Adm. burden on start-ups", "Barriers in services & network sectors",

labLevel3 = {
{{"Scope of SOEs", "Gov\[CloseCurlyQuote]t Involv. in network
sectors", "Direct control", "Governance of SOEs"}, {"Price
controls", "Command & control regulation",
"Public procurement"}, {"Assessment of impact on competition",
"Interaction with interest groups",
"Complexity of regulatory procedures"}},
{{"Adm. req. for LL com. & pers. owned enter.",
"Licenses & permits"}, {"Barriers in services sectors",
"Barriers in network sectors"}, {"Barriers to FDI",
"Tariff barriers", "Treatment of foreign suppliers",
};

level1 determines the level1 size of a rectangular represented both as numbers and percentages. Since level1 has two numbers, the rectangle will be first divided into two parts as percentages 38.63/total(level1) and 16.17/total(level1). Zooming into level1 determines percentages at the level2. The zooming in at the level3 will follow the same percentage calculation. For part 1, all the percentages will be calculated using 38.63 and for part 2, using 16.17.

part 1 and part 2 should be constructed to allow for comparability. That is, all individual percentages in both parts should be calculated over 38.63+16.17. Hence, x % in part 1 should cover the same size as x % in part 2.

For illustrative purposes I attach the following picture showing the way for calculations and the division of the original rectangle.

Similar charts exist as pie charts but not as rectangular charts. In the repository, there is no chart in rectangular format.

Another example of the appearance of the rectangle chart is:

EDIT

From @Domen, I got this code from MMA:

ResourceFunction["TreemapPlot"][level3,
"ColorFunction" -> (If[#3, ColorData[97][#.
[[1]]], White] &),
"Background" -> FaceForm[Opacity[1]]]

This correctly divides the rectangle but borders between the parts and sub-parts are not identified.

EDIT 1 see the following table for the dendrogram:

• Do you know about the resource function TreemapPlot? Sep 27, 2023 at 15:27
• I did not read into details your question because it looks more complicated than it actually is. I believe a simple ResourceFunction["TreemapPlot"][level3, "ColorFunction" -> (If[#3, ColorData[97][#[[1]]], White] &), "Background" -> FaceForm[Opacity[1]]] is exactly what you are looking for (you may want to tweak the color function to your needs). Sep 27, 2023 at 16:49
• "This correctly divides the rectangle but borders between the parts and sub-parts are not identified." -- I think MosaicPlot can be used then, but this would require the data to be re-interpeted. Sep 27, 2023 at 17:17
• Is there any logical (or problem area) dependence between the names/variables of the different levels? Sep 27, 2023 at 17:22
• Here is a link to the paclet "MosaicPlot". I will post an extended comment how it might be applied to data. Sep 27, 2023 at 17:25

You can separate levels using the option "Spacing"and associate colors with different levels using the option "ColorFunction".

In the following example, we assign colors Red and Cyan to the initial level, and ColorData[7] to the second level and, for the leaf nodes we blend White with parent node's color using rescaled node values as weights.

treeMapPlot = ResourceFunction["TreemapPlot"];

colorRules = Join[{{1} -> Red, {2} -> Cyan},
Thread[# -> (ColorData[97] /@ Range[Length @ #])] & @
Tuples[Range @ Dimensions @ level3]]

CF = Switch[Length @ #,
0, White,
1 | 2, Lighter@Lighter[ # /. colorRules],
3, Blend[{White, Take[#, 2] /. colorRules},
Rescale[#2, MinMax @ level3[[#[[1]], #[[2]]]], {.3, 1}]]] &;

tmp = treeMapPlot[level3,
"Spacing" -> .2,
"ColorFunction" -> CF,
"Background" -> FaceForm[Opacity[1]],
"FrameStyle" -> EdgeForm[Directive[Thick, White]]]

Unfortunately, treeMapPlot does not have an option to specify labels.

One way to add labels is to post-process the output to inject labels:

legendcolors = CF @@@ Flatten[MapIndexed[{#2, #} &, level3, {3}], 2];

legendlabels = Flatten[MapIndexed[Row[{Row@#2, #}, Spacer[10]] &,
Map[StringReplace[ #, "\n" -> " "] &, labLevel3, {-1}], {3}], 2];

legend =  SwatchLegend[legendcolors, legendlabels,
LegendLayout -> (Grid[#, Alignment -> Left,
Dividers -> {False,
Thread[1 + Accumulate@Flatten[Map[Length] /@ level3] -> True]}]&),
LegendMarkerSize -> 15];

ii = 0;

Legended[tmp /. Inset[_, pos_, {Center, Center}] :>
Inset[Style[(Map[Row]@indices)[[++ii]], 12], pos, {Center, Center}],
Placed[legend, Right]]

• Very nice... Can we put the level numbers inside each rectangle and add rectangle labels using swatch format? The label names are given in the question. Sep 30, 2023 at 0:11
• @Tugrul Bey, please see the updated versionl.
– kglr
Sep 30, 2023 at 1:32
• Bey: Thanks for your patience! and excellent code. Sep 30, 2023 at 17:13

## Second comment

Does the following dataset correspond to relationships in data?

If yes, can you provide the correct dataset representation?

(It is likely the one I produced below is wrong...)

pos = Position[res12, _String];
res3 = MapThread[Rule, {labLevel3, level3}, 2] /. HoldPattern[x_ -> y_] :> Thread[x -> y];
recs = Map[Append[res12[[Sequence @@ Most[#]]], res3[[Sequence @@ #]]] &, pos];
recs2 = Map[Flatten, recs /. HoldPattern[x_Rule] :> (List @@ x)];
dsRecords =
Dataset[recs2][All,
AssociationThread[{"First", "Second", "Third", "Value"}, #] &] /. x_String :> StringReplace[x, (WhitespaceCharacter ..) -> " "]

## First comment

PacletInstall["AntonAntonov/MosaicPlot"];
Needs["AntonAntonovMosaicPlot"];
lsLevel1 = (Prepend[List @@ #1, "1"] &) /@ MapThread[Rule, {labLevel1, level1}];
lsLevel12 = (Prepend[List @@ #1, "2"] &) /@ Flatten[MapThread[Rule, {labLevel2, level2}, 2]];
res3 = MapThread[Rule, {labLevel3, level3}, 2] /. HoldPattern[x_ -> y_] :> Thread[x -> y];
lsLevel13 = (Prepend[List @@ #1, "3"] &) /@ Flatten[res3];
lsArr = Join[lsLevel1, lsLevel12, lsLevel13];
MosaicPlot[lsArr, "ExpandLastColumn" -> True, "LabelRotation" -> {{1, 0.2}, {0, 1}}, "ZeroProbability" -> 0]

• Thanks for this quick reply. Your code does not really fit into what I am after. I simply want to represent three layers (connected to each other) in a rectangle so as to compare all three layers at the same time by just looking at the chart. Sep 27, 2023 at 17:44
• Please, see my update. Sep 27, 2023 at 18:51
• Unfortunately, your data set has missing level3 elements. For example, in level2, public ownership has 4 sub-items; while level2 involvement in business has 3 sub-items. In your dataset, all of them have 2 sub-items. The structure is precisely given in the table I sent earlier. Just see each column with a varying number of sub-items. Sep 27, 2023 at 20:24
• In EDIT 1, I gave the dendrogram for the levels and variables. Sep 27, 2023 at 20:29
• Is this image of the table you are referring to? Sep 27, 2023 at 20:31