comparison flys-artifacts/src/main/java/de/intevation/flys/exports/XYChartGenerator.java @ 2584:5d5457a1bd5f

Stubby legend aggregation. flys-artifacts/trunk@4136 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Felix Wolfsteller <felix.wolfsteller@intevation.de>
date Fri, 09 Mar 2012 12:57:23 +0000
parents 3598690dc9e2
children bece6f604899
comparison
equal deleted inserted replaced
2583:046d5c82ea0c 2584:5d5457a1bd5f
8 8
9 import java.text.NumberFormat; 9 import java.text.NumberFormat;
10 10
11 import java.util.ArrayList; 11 import java.util.ArrayList;
12 import java.util.HashMap; 12 import java.util.HashMap;
13 import java.util.Iterator;
13 import java.util.List; 14 import java.util.List;
15 import java.util.LinkedHashMap;
14 import java.util.Map; 16 import java.util.Map;
15 17
16 import org.w3c.dom.Document; 18 import org.w3c.dom.Document;
17 19
18 import org.apache.log4j.Logger; 20 import org.apache.log4j.Logger;
19 21
20 import org.jfree.chart.ChartFactory; 22 import org.jfree.chart.ChartFactory;
21 import org.jfree.chart.JFreeChart; 23 import org.jfree.chart.JFreeChart;
24 import org.jfree.chart.LegendItem;
22 import org.jfree.chart.LegendItemCollection; 25 import org.jfree.chart.LegendItemCollection;
23 import org.jfree.chart.annotations.XYBoxAnnotation; 26 import org.jfree.chart.annotations.XYBoxAnnotation;
24 import org.jfree.chart.annotations.XYLineAnnotation; 27 import org.jfree.chart.annotations.XYLineAnnotation;
25 import org.jfree.chart.annotations.XYTextAnnotation; 28 import org.jfree.chart.annotations.XYTextAnnotation;
26 import org.jfree.chart.axis.NumberAxis; 29 import org.jfree.chart.axis.NumberAxis;
228 adjustAxes(plot); 231 adjustAxes(plot);
229 autoZoom(plot); 232 autoZoom(plot);
230 233
231 // These have to go after the autozoom. 234 // These have to go after the autozoom.
232 addAnnotationsToRenderer(plot); 235 addAnnotationsToRenderer(plot);
236
237 aggregateLegendEntries(plot);
233 238
234 return chart; 239 return chart;
235 } 240 }
236 241
237 242
1020 doAnnotations(annotations, null, theme, visible); 1025 doAnnotations(annotations, null, theme, visible);
1021 addAxisSeries(series, axisIndex, visible); 1026 addAxisSeries(series, axisIndex, visible);
1022 } 1027 }
1023 1028
1024 1029
1030 /**
1031 * Create a hash from a legenditem.
1032 * This hash can then be used to merge legend items labels.
1033 * @return hash for given legenditem to identify mergeables.
1034 */
1035 public static String legendItemHash(LegendItem li) {
1036 // TODO Do proper implementation. Ensure that only mergable sets are created.
1037 // getFillPaint()
1038 // getFillPaintTransformer()
1039 // getLabel()
1040 // getLine()
1041 // getLinePaint()
1042 // getLineStroke()
1043 // getOutlinePaint()
1044 // getOutlineStroke()
1045 // Shape getShape()
1046 // String getToolTipText()
1047 // String getURLText()
1048 // boolean isLineVisible()
1049 // boolean isShapeFilled()
1050 // boolean isShapeOutlineVisible()
1051 // boolean isShapeVisible()
1052 return li.getLinePaint().toString();
1053 }
1054
1055
1056 /**
1057 * Create a label for multiple items.
1058 *
1059 * For example from "W(Q=100)" and "W(Q=220)"
1060 * "W(Q= {100, 22})" would result.
1061 *
1062 * @param items list of legenditems.
1063 * @return the merged label.
1064 */
1065 public String mergeLegendNames(List<LegendItem> items) {
1066 if (items.size() == 0) {
1067 return null;
1068 }
1069 if (items.size() == 1) {
1070 return items.get(0).getLabel();
1071 }
1072 // TODO consider using regionMathches for implementation.
1073 int lastMatchedChar = 0;
1074 boolean first = true;
1075 String startPattern = "";
1076 String endPattern = "";
1077 String name = "";
1078 // First, figure out beginning and end patterns, then merge.
1079 for (LegendItem item : items) {
1080 if (first) {
1081 startPattern = item.getLabel();
1082 endPattern = item.getLabel();
1083 first = false;
1084 continue;
1085 }
1086 while (startPattern.length() > 0 && !item.getLabel().startsWith(startPattern)) {
1087 startPattern = startPattern.substring(0, startPattern.length() -1);
1088 }
1089 while (endPattern.length() > 0 && !item.getLabel().endsWith(endPattern)) {
1090 endPattern = endPattern.substring(1);
1091 }
1092 }
1093
1094 // Then, merge.
1095 name = startPattern + " {";
1096 first = true;
1097 for (LegendItem item : items) {
1098 if (!first) {
1099 name += ", ";
1100 }
1101 else {
1102 first = false;
1103 }
1104 name += item.getLabel().substring(startPattern.length(),
1105 item.getLabel().length() - endPattern.length());
1106 }
1107 name += "} ";
1108 name += endPattern;
1109
1110 return name;
1111 }
1112
1113
1114 /**
1115 * Create new legend entries, dependant on settings.
1116 * @param plot The plot for which to modify the legend.
1117 */
1118 public void aggregateLegendEntries(XYPlot plot) {
1119 LegendItemCollection old = plot.getLegendItems();
1120 // Find "similar" entries if aggregation is enabled.
1121
1122 int maxListSize = 0;
1123 int AGGR_THRESHOLD = 2;
1124
1125 HashMap<String, List<LegendItem>> entries = new LinkedHashMap<String, List<LegendItem>>();
1126 for (Iterator i = old.iterator(); i.hasNext();) {
1127 LegendItem item = (LegendItem) i.next();
1128 String hash = legendItemHash(item);
1129 List<LegendItem> itemList = entries.get(hash);
1130 if (itemList == null) {
1131 itemList = new ArrayList<LegendItem>();
1132 }
1133 itemList.add(item);
1134
1135 if (itemList.size() > maxListSize) {
1136 maxListSize = itemList.size();
1137 }
1138
1139 entries.put(legendItemHash(item), itemList);
1140 }
1141
1142 if (maxListSize < AGGR_THRESHOLD) {
1143 // No need to do anything.
1144 return;
1145 }
1146
1147 // Run over collected entries, merge their names and create new
1148 // entry if needed.
1149 LegendItemCollection newLegend = new LegendItemCollection();
1150 for (Map.Entry<String, List<LegendItem>> cursor: entries.entrySet()) {
1151 List<LegendItem> itemList = cursor.getValue();
1152 if (itemList.size() >= AGGR_THRESHOLD) {
1153 // TODO now do merging
1154 }
1155 else {
1156 // TODO create singular new entry
1157 }
1158
1159 LegendItem item = (LegendItem) itemList.get(0);
1160 // Unfortunately we cannot clone and just setDescription, as this
1161 // method was added in JFreeChart 1.0.14 (we are at .13).
1162 LegendItem merged = new LegendItem(
1163 mergeLegendNames(itemList), item.getDescription(), item.getToolTipText(),
1164 item.getURLText(), item.isShapeVisible(), item.getShape(),
1165 item.isShapeFilled(), item.getFillPaint(), item.isShapeOutlineVisible(),
1166 item.getOutlinePaint(), item.getOutlineStroke(), item.isLineVisible(),
1167 item.getLine(), item.getLineStroke(), item.getLinePaint());
1168 newLegend.add(merged);
1169 }
1170
1171 plot.setFixedLegendItems (newLegend);
1172 }
1173
1174
1025 /** Two Ranges that span a rectangular area. */ 1175 /** Two Ranges that span a rectangular area. */
1026 public static class Area { 1176 public static class Area {
1027 protected Range xRange; 1177 protected Range xRange;
1028 protected Range yRange; 1178 protected Range yRange;
1029 1179

http://dive4elements.wald.intevation.org