diff --git a/pic-sure-resources/pic-sure-visualization-resource/src/test/java/edu/harvard/hms/dbmi/avillach/resource/visualization/service/VisualizationUtilTests.java b/pic-sure-resources/pic-sure-visualization-resource/src/test/java/edu/harvard/hms/dbmi/avillach/resource/visualization/service/VisualizationUtilTests.java new file mode 100644 index 00000000..78583922 --- /dev/null +++ b/pic-sure-resources/pic-sure-visualization-resource/src/test/java/edu/harvard/hms/dbmi/avillach/resource/visualization/service/VisualizationUtilTests.java @@ -0,0 +1,94 @@ +package edu.harvard.hms.dbmi.avillach.resource.visualization.service; + +import edu.harvard.dbmi.avillach.util.VisualizationUtil; +import org.junit.Test; +import org.junit.jupiter.api.DisplayName; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +public class VisualizationUtilTests { + + @Test + @DisplayName("Test limitKeySize") + public void testLimitKeySizeUniqueness() { + Map axisMap = new HashMap<>(Map.of( + "Disease-Specific (Asthma, Allergy and Inflammation, PUB)", 1, + "Disease-Specific (Asthma, Allergy and Inflammation, PUB, NPU)", 1, + "Disease-Specific (Asthma, Allergy and Inflammation, NPU)", 1, + "Disease-Specific (Asthma, Allergy and Inflammation)", 1 + )); + + Map actual = VisualizationUtil.limitKeySize(axisMap); + + Map expected = Map.of( + "Disease-Specific (Asthma, Allergy an..., PUB)", 1, + "Disease-Specific (Asthma, Allergy an...ation)", 1, + "Disease-Specific (Asthma, Allergy an..., NPU)", 1, + "Disease-Specific (Asthma, Allergy a...B, NPU)", 1 + ); + assertEquals(expected, actual); + } + + @Test + @DisplayName("Test Empty Map limitKeySize") + public void testEmptyMapLimitKeySize() { + Map axisMap = new HashMap<>(); + Map actual = VisualizationUtil.limitKeySize(axisMap); + Map expected = new HashMap<>(); + assertEquals(expected, actual); + } + + @Test + @DisplayName("Test null Map limitKeySize") + public void testNullMapLimitKeySize() { + Map axisMap = null; + // this should throw a NullPointerException + try { + VisualizationUtil.limitKeySize(axisMap); + } catch (IllegalArgumentException e) { + assertEquals("axisMap cannot be null", e.getMessage()); + } + } + + @Test + @DisplayName("Test with no long keys limitKeySize") + public void testNoLongKeysLimitKeySize() { + // Test with no long keys + Map axisMap = new HashMap<>(); + for (int i = 0; i < 10; i++) { + axisMap.put("key" + i, 1); + } + Map actual = VisualizationUtil.limitKeySize(axisMap); + Map expected = new HashMap<>(axisMap); + assertEquals(expected, actual); + } + + @Test + @DisplayName("Test with keys of greater than 45 characters and uniqueness is near middle limitKeySize") + public void testKeysOfGreaterLengthAndUniquenessNearMiddleLimitKeySize() { + Map axisMap = new HashMap<>(); + axisMap.put("Hello, this is a long key that is STRING1 greater than 45 characters and is unique", 1); + axisMap.put("Hello, this is a long key that is STRING2 greater than 45 characters and is unique", 1); + axisMap.put("Hello, this is a long key that is STRING3 greater than 45 characters and is unique", 1); + + Map actual = VisualizationUtil.limitKeySize(axisMap); + + // loop through the keys and check if they are less than 45 characters + for (String key : actual.keySet()) { + assertEquals(45, key.length()); + } + + Map expected = Map.of( + "Hello, this is a long key that is ST...unique", 1, + "Hello, this is a long key that is S... unique", 1, + "Hello, this is a long key that is ...s unique", 1 + ); + + assertEquals(expected, actual); + } + + +} diff --git a/pic-sure-util/src/main/java/edu/harvard/dbmi/avillach/util/VisualizationUtil.java b/pic-sure-util/src/main/java/edu/harvard/dbmi/avillach/util/VisualizationUtil.java index 8a7d99a7..ed32a921 100644 --- a/pic-sure-util/src/main/java/edu/harvard/dbmi/avillach/util/VisualizationUtil.java +++ b/pic-sure-util/src/main/java/edu/harvard/dbmi/avillach/util/VisualizationUtil.java @@ -69,25 +69,50 @@ public static Map doProcessResults(Map axisMap } /** - * Replaces long column names with shorter version. + * This method is used to limit the size of the keys in the axisMap to a maximum of 45 characters. If the key is longer + * than 45 characters, it will be shortened to 45 characters and the last 3 characters will be replaced with "...". + * If the shortened key is not unique, we will create a unique one + *

* - * @param axisMap - * @return + * @param axisMap - Map of the categories and their counts + * @return Map - Map of the categories and their counts with the keys limited to 45 characters */ - private static Map limitKeySize(Map axisMap) { - List toRemove = new ArrayList<>(); - Map toAdd = new HashMap<>(); - axisMap.keySet().forEach(key -> { - if (key.length() > MAX_X_LABEL_LINE_LENGTH) { - toRemove.add(key); - toAdd.put( - key.substring(0, MAX_X_LABEL_LINE_LENGTH - 3) + "...", - axisMap.get(key)); - } + public static Map limitKeySize(Map axisMap) { + if (axisMap == null) { + throw new IllegalArgumentException("axisMap cannot be null"); + } + + Map newAxisMap = new HashMap<>(); + HashSet keys = new HashSet<>(); + axisMap.forEach((key, value) -> { + String adjustedKey = key.length() < MAX_X_LABEL_LINE_LENGTH ? key : createAdjustedKey(axisMap, keys, key); + newAxisMap.put(adjustedKey, value); + keys.add(adjustedKey); }); - toRemove.forEach(key -> axisMap.remove(key)); - axisMap.putAll(toAdd); - return axisMap; + return newAxisMap; + } + + private static String createAdjustedKey(Map axisMap, HashSet keys, String key) { + String keyPrefix = key.substring(0, MAX_X_LABEL_LINE_LENGTH); + return isKeyPrefixInAxisMap(axisMap, keyPrefix) ? generateUniqueKey(keys, key) : appendEllipsis(keyPrefix); + } + + private static boolean isKeyPrefixInAxisMap(Map axisMap, String keyPrefix) { + return axisMap.keySet().stream().anyMatch(k -> k.startsWith(keyPrefix)); + } + + private static String generateUniqueKey(HashSet keys, String key) { + int countFromEnd = 6; + String proposedKey; + do { + proposedKey = String.format("%s...%s", key.substring(0, MAX_X_LABEL_LINE_LENGTH - 3 - countFromEnd), key.substring(key.length() - countFromEnd)); + countFromEnd++; + } while (keys.contains(proposedKey)); + return proposedKey; + } + + private static String appendEllipsis(String keyPrefixAdjusted) { + return String.format("%s...", keyPrefixAdjusted); } }