/*
* RapidMiner
*
* Copyright (C) 2001-2014 by RapidMiner and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapidminer.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.rapidminer.gui.new_plotter.templates;
import java.awt.Color;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import com.rapidminer.datatable.DataTable;
import com.rapidminer.datatable.DataTableExampleSetAdapter;
import com.rapidminer.example.ExampleSet;
import com.rapidminer.gui.new_plotter.ChartConfigurationException;
import com.rapidminer.gui.new_plotter.configuration.AxisParallelLineConfiguration;
import com.rapidminer.gui.new_plotter.configuration.DataTableColumn;
import com.rapidminer.gui.new_plotter.configuration.DefaultDimensionConfig;
import com.rapidminer.gui.new_plotter.configuration.DimensionConfig.PlotDimension;
import com.rapidminer.gui.new_plotter.configuration.DistinctValueGrouping;
import com.rapidminer.gui.new_plotter.configuration.EquidistantFixedBinCountBinning;
import com.rapidminer.gui.new_plotter.configuration.LegendConfiguration.LegendPosition;
import com.rapidminer.gui.new_plotter.configuration.LineFormat.LineStyle;
import com.rapidminer.gui.new_plotter.configuration.PlotConfiguration;
import com.rapidminer.gui.new_plotter.configuration.RangeAxisConfig;
import com.rapidminer.gui.new_plotter.configuration.SeriesFormat;
import com.rapidminer.gui.new_plotter.configuration.SeriesFormat.VisualizationType;
import com.rapidminer.gui.new_plotter.configuration.ValueGrouping.GroupingType;
import com.rapidminer.gui.new_plotter.configuration.ValueGrouping.ValueGroupingFactory;
import com.rapidminer.gui.new_plotter.configuration.ValueSource;
import com.rapidminer.gui.new_plotter.data.PlotInstance;
import com.rapidminer.gui.new_plotter.templates.gui.HistogrammTemplatePanel;
import com.rapidminer.gui.new_plotter.templates.style.ColorRGB;
import com.rapidminer.gui.new_plotter.templates.style.PlotterStyleProvider;
import com.rapidminer.gui.new_plotter.utility.DataTransformation;
import com.rapidminer.tools.I18N;
import com.rapidminer.tools.LogService;
import com.rapidminer.tools.math.function.aggregation.AbstractAggregationFunction.AggregationFunctionType;
/**
* The template for a histogram plot.
*
* @author Marco Boeck
*
*/
public class HistogramTemplate extends PlotterTemplate {
private static final String PLOT_NAME_ELEMENT = "plotName";
private static final String PLOT_NAMES_ELEMENT = "plotNames";
private static final String OPAQUE_ELEMENT = "opaque";
private static final String BINS_ELEMENT = "bins";
private static final String USE_ABSOLUTE_VALUES_ELEMENT = "useAbsoluteValues";
private static final String Y_AXIS_LOGARITHMIC_ELEMENT = "yAxisLogarithmic";
/** the current {@link DataTable} backup */
private DataTable currentDataTableBackup;
/** the original {@link DataTable} */
private DataTable modifiedDataTable;
/** the current {@link RangeAxisConfig}s */
private List<RangeAxisConfig> currentRangeAxisConfigsList;
/** the names of the plots to show */
private Object[] plotNames;
/** the number of bins */
private int bins;
/** the opaque value */
private int opaque;
/** determines if absolute values are used */
private boolean useAbsoluteValues;
/** determines if the range (Y) axis should be logarithmic */
private boolean yAxisLogarithmic;
/**
* Creates a new {@link HistogramTemplate}. This template allows easy configuration
* of the histogram chart for the plotter.
*/
public HistogramTemplate() {
currentRangeAxisConfigsList = new LinkedList<RangeAxisConfig>();
bins = 40;
opaque = 255;
useAbsoluteValues = false;
yAxisLogarithmic = false;
plotNames = new Object[0];
guiPanel = new HistogrammTemplatePanel(this);
}
@Override
public String getChartType() {
return HistogramTemplate.getI18NName();
}
/**
* Sets the number of bins.
* @param bins must be >0 and <=100
*/
public void setBins(int bins) {
if (bins <= 0 || bins > 100) {
throw new IllegalArgumentException("bins must be > 0 and <= 100!");
}
this.bins = bins;
updatePlotConfiguration();
setChanged();
notifyObservers();
}
/**
* Returns the number of bins.
* @return
*/
public int getBins() {
return bins;
}
/**
* Sets the opacity.
* @param opaque must be >=0 and <=255
*/
public void setOpaque(int opaque) {
if (opaque < 0 || opaque > 255) {
throw new IllegalArgumentException("opaque must be >= 0 and <= 255!");
}
this.opaque = opaque;
updatePlotConfiguration();
setChanged();
notifyObservers();
}
/**
* Returns the opacity.
* @return
*/
public int getOpacity() {
return opaque;
}
@Override
protected void dataUpdated(final DataTable dataTable) {
currentDataTable = dataTable;
// convert to meta information DataTable
updateMetaDataTable(currentDataTable);
// clear possible existing data
currentRangeAxisConfigsList.clear();
}
/**
* Converts a {@link DataTable} to the meta data {@link DataTable} which is used by the {@link HistogramTemplate}.
* @param dataTable the original {@link DataTable}
*/
private void updateMetaDataTable(final DataTable dataTable) {
List<String> selectedNumericAttributes = new ArrayList<String>(plotNames.length);
for (Object name : plotNames) {
selectedNumericAttributes.add(String.valueOf(name));
}
ExampleSet newExampleSet = DataTableExampleSetAdapter.createExampleSetFromDataTable(dataTable);
ExampleSet metaSet = DataTransformation.createDePivotizedExampleSet(newExampleSet, selectedNumericAttributes);
// in case of error or no attributes specified
if (metaSet == null) {
return;
}
modifiedDataTable = new DataTableExampleSetAdapter(metaSet, null);
PlotConfiguration plotConfiguration = new PlotConfiguration(new DataTableColumn(modifiedDataTable, 0));
PlotInstance newPlotInstance = new PlotInstance(plotConfiguration, modifiedDataTable);
// only set plotInstance if plotEngine currently displays the HistogramTemplate plotInstance
// otherwise we would take another template the plotEngine away
if (plotEngine.getPlotInstance() == getPlotInstance()) {
plotEngine.setPlotInstance(newPlotInstance);
}
setPlotInstance(newPlotInstance);
}
/**
* Gets the current {@link DataTable} for this {@link HistogramTemplate}.
* Based on this a new {@link DataTable} can be created and given to the template via
* {@link #replaceTemporarilyCurrentDataTable(DataTable)}.
* @return
*/
public DataTable getCurrentDataTable() {
return this.currentDataTable;
}
/**
* Replaces the current {@link DataTable} with the given one.
* Can be used to filter the data for the histogram based on certain conditions.
* @param replacementTable
* @param createBackup if set to false, will NOT create a new backup. Use if chaining these calls
* without calling {@link #revertToBackupDataTable()}.
*/
public void replaceTemporarilyCurrentDataTable(DataTable replacementTable, boolean createBackup) {
if (createBackup) {
currentDataTableBackup = currentDataTable;
}
currentDataTable = replacementTable;
// convert to meta information DataTable
updateMetaDataTable(currentDataTable);
updatePlotConfiguration();
setChanged();
notifyObservers();
}
/**
* Returns the current {@link DataTable} back to the original.
* If it has not been modified via {@link #replaceTemporarilyCurrentDataTable(DataTable)},
* nothing happens.
*/
public void revertToBackupDataTable() {
if (currentDataTableBackup == null) {
return;
}
currentDataTable = currentDataTableBackup;
currentDataTableBackup = null;
// convert to meta information DataTable
updateMetaDataTable(currentDataTable);
updatePlotConfiguration();
setChanged();
notifyObservers();
}
/**
* Returns <code>true</code> if a backup of the current {@link DataTable} exists.
* @return
*/
public boolean hasBackupDataTable() {
return currentDataTableBackup != null;
}
/**
* Gets the backup {@link DataTable} for this {@link HistogramTemplate}.
* Check prior to calling via {@link #hasBackupDataTable()}, otherwise you might
* get <code>null</code> as return value.
* @return
*/
public DataTable getBackupDataTable() {
return currentDataTableBackup;
}
/**
* Sets whether absolute values should be used or not.
* @param useAbsoluteValues
*/
public void setUseAbsoluteValues(boolean useAbsoluteValues) {
this.useAbsoluteValues = useAbsoluteValues;
updatePlotConfiguration();
setChanged();
notifyObservers();
}
/**
* Returns whether absolute values are used or not.
* @return
*/
public boolean isUsingAbsoluteValues() {
return useAbsoluteValues;
}
/**
* Sets whether the range (Y) axis should be logarithmic or not.
* @param yAxisLogarithmic
*/
public void setYAxisLogarithmic(boolean yAxisLogarithmic) {
this.yAxisLogarithmic = yAxisLogarithmic;
updatePlotConfiguration();
setChanged();
notifyObservers();
}
/**
* Returns whether the range (Y) axis is logarithmic or not.
* @return
*/
public boolean isYAxisLogarithmic() {
return yAxisLogarithmic;
}
/**
* Sets the currently selected plots by their name.
* @param plotNames
*/
public void setPlotSelection(Object[] plotNames) {
this.plotNames = plotNames;
// plot selection has changed, update meta information DataTable
updateMetaDataTable(currentDataTable);
updatePlotConfiguration();
setChanged();
notifyObservers();
}
/**
* Returns the currently selected plots.
* @return
*/
public Object[] getPlotSelection() {
return plotNames;
}
public static String getI18NName() {
return I18N.getMessage(I18N.getGUIBundle(), "gui.plotter.histogram.name");
}
@Override
protected void updatePlotConfiguration() {
// don't do anything if updates are suspended due to batch updating
if (suspendUpdates) {
return;
}
PlotConfiguration plotConfiguration = plotInstance.getMasterPlotConfiguration();
// stop event processing
boolean plotConfigurationProcessedEvents = plotConfiguration.isProcessingEvents();
plotConfiguration.setProcessEvents(false);
// remove old config(s)
for (RangeAxisConfig rAConfig : currentRangeAxisConfigsList) {
if (plotConfiguration.getIndexOfRangeAxisConfigById(rAConfig.getId()) != -1) {
rAConfig.removeRangeAxisConfigListener(rangeAxisConfigListener);
plotConfiguration.removeRangeAxisConfig(rAConfig);
}
}
currentRangeAxisConfigsList.clear();
// no selection?
if (plotNames.length == 0) {
plotConfiguration.setProcessEvents(plotConfigurationProcessedEvents);
return;
}
try {
DataTableColumn valueTableColumn = new DataTableColumn(modifiedDataTable, modifiedDataTable.getColumnIndex("value"));
DataTableColumn attributeTableColumn = new DataTableColumn(modifiedDataTable, modifiedDataTable.getColumnIndex("attribute"));
// set binning
EquidistantFixedBinCountBinning newValueGrouping;
newValueGrouping = (EquidistantFixedBinCountBinning) ValueGroupingFactory.getValueGrouping(GroupingType.EQUIDISTANT_FIXED_BIN_COUNT, valueTableColumn, false, DateFormat.getDateTimeInstance());
newValueGrouping.setBinCount(bins);
plotConfiguration.getDomainConfigManager().setGrouping(newValueGrouping);
plotConfiguration.getDomainConfigManager().setDataTableColumn(valueTableColumn);
// restore crosshairs
List<AxisParallelLineConfiguration> clonedListOfDomainLines = new LinkedList<AxisParallelLineConfiguration>(listOfDomainLines);
for (AxisParallelLineConfiguration lineConfig : clonedListOfDomainLines) {
plotConfiguration.getDomainConfigManager().getCrosshairLines().addLine(lineConfig);
}
RangeAxisConfig newRangeAxisConfig = new RangeAxisConfig(null, plotConfiguration);
ValueSource valueSource;
valueSource = new ValueSource(plotConfiguration, attributeTableColumn, AggregationFunctionType.count, true);
valueSource.setUseDomainGrouping(true);
SeriesFormat sFormat = new SeriesFormat();
sFormat.setSeriesType(VisualizationType.BARS);
sFormat.setOpacity(opaque);
valueSource.setSeriesFormat(sFormat);
newRangeAxisConfig.addValueSource(valueSource, null);
newRangeAxisConfig.setLogarithmicAxis(yAxisLogarithmic);
newRangeAxisConfig.addRangeAxisConfigListener(rangeAxisConfigListener);
// add new config(s) and restore crosshairs
List<AxisParallelLineConfiguration> clonedRangeAxisLineList = rangeAxisCrosshairLinesMap.get(newRangeAxisConfig.getLabel());
if (clonedRangeAxisLineList != null) {
for (AxisParallelLineConfiguration lineConfig : clonedRangeAxisLineList) {
newRangeAxisConfig.getCrossHairLines().addLine(lineConfig);
}
}
plotConfiguration.addRangeAxisConfig(newRangeAxisConfig);
// remember the new config so we can remove it later again
currentRangeAxisConfigsList.add(newRangeAxisConfig);
plotConfiguration.setDimensionConfig(PlotDimension.COLOR, null);
DefaultDimensionConfig dimConfig = new DefaultDimensionConfig(plotConfiguration, attributeTableColumn, PlotDimension.COLOR);
dimConfig.setGrouping(new DistinctValueGrouping(attributeTableColumn, true, null));
plotConfiguration.setDimensionConfig(PlotDimension.COLOR, dimConfig);
// general settings
plotConfiguration.setAxesFont(styleProvider.getAxesFont());
plotConfiguration.setTitleFont(styleProvider.getTitleFont());
plotConfiguration.getLegendConfiguration().setLegendFont(styleProvider.getLegendFont());
plotConfiguration.addColorSchemeAndSetActive(styleProvider.getColorScheme());
if (styleProvider.isShowLegend()) {
plotConfiguration.getLegendConfiguration().setLegendPosition(LegendPosition.BOTTOM);
} else {
plotConfiguration.getLegendConfiguration().setLegendPosition(LegendPosition.NONE);
}
plotConfiguration.setFrameBackgroundColor(ColorRGB.convertToColor(styleProvider.getFrameBackgroundColor()));
plotConfiguration.setPlotBackgroundColor(ColorRGB.convertToColor(styleProvider.getPlotBackgroundColor()));
plotConfiguration.setTitleText(styleProvider.getTitleText());
} catch (ChartConfigurationException e) {
//LogService.getRoot().log(Level.WARNING, "Chart could not be configured.", e);
LogService.getRoot().log(Level.WARNING,
I18N.getMessage(LogService.getRoot().getResourceBundle(),
"com.rapidminer.gui.new_plotter.templates.HistrogramTemplate.configurating_chart_error"),
e);
} finally {
// continue event processing
plotConfiguration.setProcessEvents(plotConfigurationProcessedEvents);
}
}
@Override
public Element writeToXML(Document document) {
Element template = document.createElement(PlotterTemplate.TEMPLATE_ELEMENT);
template.setAttribute(PlotterTemplate.NAME_ELEMENT, getChartType());
Element setting;
setting = document.createElement(Y_AXIS_LOGARITHMIC_ELEMENT);
setting.setAttribute(VALUE_ATTRIBUTE, String.valueOf(yAxisLogarithmic));
template.appendChild(setting);
setting = document.createElement(USE_ABSOLUTE_VALUES_ELEMENT);
setting.setAttribute(VALUE_ATTRIBUTE, String.valueOf(useAbsoluteValues));
template.appendChild(setting);
setting = document.createElement(BINS_ELEMENT);
setting.setAttribute(VALUE_ATTRIBUTE, String.valueOf(bins));
template.appendChild(setting);
setting = document.createElement(OPAQUE_ELEMENT);
setting.setAttribute(VALUE_ATTRIBUTE, String.valueOf(opaque));
template.appendChild(setting);
setting = document.createElement(PLOT_NAMES_ELEMENT);
for (Object key : plotNames) {
Element plotNameElement = document.createElement(PLOT_NAME_ELEMENT);
plotNameElement.setAttribute(VALUE_ATTRIBUTE, String.valueOf(key));
setting.appendChild(plotNameElement);
}
template.appendChild(setting);
// store crosshairs (RangeAxis)
setting = document.createElement(CROSSHAIR_RANGE_AXIS_TOP_ELEMENT);
for (String rangeAxisLabel : rangeAxisCrosshairLinesMap.keySet()) {
// add crosshairs of currently not displayed range axes
List<AxisParallelLineConfiguration> lines = rangeAxisCrosshairLinesMap.get(rangeAxisLabel);
if (lines != null) {
for (AxisParallelLineConfiguration line : lines) {
Element rangeCrosshairElement = document.createElement(CROSSHAIR_RANGE_AXIS_ELEMENT);
rangeCrosshairElement.setAttribute(CROSSHAIR_RANGE_AXIS_LABEL_ATTRIBUTE, rangeAxisLabel);
rangeCrosshairElement.setAttribute(CROSSHAIR_VALUE_ATTRIBUTE, String.valueOf(line.getValue()));
rangeCrosshairElement.setAttribute(CROSSHAIR_WIDTH_ATTRIBUTE, String.valueOf(line.getFormat().getWidth()));
rangeCrosshairElement.setAttribute(CROSSHAIR_STYLE_ATTRIBUTE, String.valueOf(line.getFormat().getStyle()));
Element colorElement = document.createElement(CROSSHAIR_COLOR_ELEMENT);
colorElement.setAttribute(CROSSHAIR_COLOR_R_ATTRIBUTE, String.valueOf(line.getFormat().getColor().getRed()));
colorElement.setAttribute(CROSSHAIR_COLOR_G_ATTRIBUTE, String.valueOf(line.getFormat().getColor().getGreen()));
colorElement.setAttribute(CROSSHAIR_COLOR_B_ATTRIBUTE, String.valueOf(line.getFormat().getColor().getBlue()));
rangeCrosshairElement.appendChild(colorElement);
setting.appendChild(rangeCrosshairElement);
}
}
}
template.appendChild(setting);
// store crosshairs (domainAxis)
setting = document.createElement(CROSSHAIR_DOMAIN_TOP_ELEMENT);
Element domainCrosshairElement = document.createElement(CROSSHAIR_DOMAIN_ELEMENT);
for (AxisParallelLineConfiguration line : listOfDomainLines) {
domainCrosshairElement.setAttribute(CROSSHAIR_VALUE_ATTRIBUTE, String.valueOf(line.getValue()));
domainCrosshairElement.setAttribute(CROSSHAIR_WIDTH_ATTRIBUTE, String.valueOf(line.getFormat().getWidth()));
domainCrosshairElement.setAttribute(CROSSHAIR_STYLE_ATTRIBUTE, String.valueOf(line.getFormat().getStyle()));
Element colorElement = document.createElement(CROSSHAIR_COLOR_ELEMENT);
colorElement.setAttribute(CROSSHAIR_COLOR_R_ATTRIBUTE, String.valueOf(line.getFormat().getColor().getRed()));
colorElement.setAttribute(CROSSHAIR_COLOR_G_ATTRIBUTE, String.valueOf(line.getFormat().getColor().getGreen()));
colorElement.setAttribute(CROSSHAIR_COLOR_B_ATTRIBUTE, String.valueOf(line.getFormat().getColor().getBlue()));
domainCrosshairElement.appendChild(colorElement);
setting.appendChild(domainCrosshairElement);
}
template.appendChild(setting);
template.appendChild(styleProvider.createXML(document));
return template;
}
@Override
public void loadFromXML(Element templateElement) {
suspendUpdates = true;
for (int i=0; i<templateElement.getChildNodes().getLength(); i++) {
Node node = templateElement.getChildNodes().item(i);
if (node instanceof Element) {
Element setting = (Element) node;
if (setting.getNodeName().equals(PLOT_NAMES_ELEMENT)) {
List<Object> plotNamesList = new LinkedList<Object>();
for (int j=0; j<setting.getChildNodes().getLength(); j++) {
Node plotNode = setting.getChildNodes().item(j);
if (plotNode instanceof Element) {
Element plotNameElement = (Element) plotNode;
if (plotNameElement.getNodeName().equals(PLOT_NAME_ELEMENT)) {
plotNamesList.add(plotNameElement.getAttribute(VALUE_ATTRIBUTE));
}
}
}
setPlotSelection(plotNamesList.toArray());
} else if (setting.getNodeName().equals(USE_ABSOLUTE_VALUES_ELEMENT)) {
setUseAbsoluteValues(Boolean.parseBoolean(setting.getAttribute(VALUE_ATTRIBUTE)));
} else if (setting.getNodeName().equals(Y_AXIS_LOGARITHMIC_ELEMENT)) {
setYAxisLogarithmic(Boolean.parseBoolean(setting.getAttribute(VALUE_ATTRIBUTE)));
} else if (setting.getNodeName().equals(BINS_ELEMENT)) {
try {
setBins(Integer.parseInt(setting.getAttribute(VALUE_ATTRIBUTE)));
} catch (NumberFormatException e) {
//LogService.getRoot().warning("Could not restore bins setting for histogram template!");
LogService.getRoot().log(Level.WARNING,
I18N.getMessage(LogService.getRoot().getResourceBundle(),
"com.rapidminer.gui.new_plotter.templates.HistrogramTemplate.restoring_bins_setting_error"),
e);
}
} else if (setting.getNodeName().equals(OPAQUE_ELEMENT)) {
try {
setOpaque(Integer.parseInt(setting.getAttribute(VALUE_ATTRIBUTE)));
} catch (NumberFormatException e) {
//LogService.getRoot().warning("Could not restore opaque setting for histogram template!");
LogService.getRoot().log(Level.WARNING,
I18N.getMessage(LogService.getRoot().getResourceBundle(),
"com.rapidminer.gui.new_plotter.templates.HistrogramTemplate.restoring_opaque_setting_error"),
e);
}
} else if (setting.getNodeName().equals(CROSSHAIR_RANGE_AXIS_TOP_ELEMENT)) {
try {
// load range axes crosshairs
for (int j=0; j<setting.getChildNodes().getLength(); j++) {
Node rangeCrosshairNode = setting.getChildNodes().item(j);
if (rangeCrosshairNode instanceof Element) {
Element rangeCrosshairElement = (Element) rangeCrosshairNode;
if (rangeCrosshairElement.getNodeName().equals(CROSSHAIR_RANGE_AXIS_ELEMENT)) {
// load range axis crosshair
AxisParallelLineConfiguration line = new AxisParallelLineConfiguration(1.0, false);
String rangeAxisLabel = rangeCrosshairElement.getAttribute(CROSSHAIR_RANGE_AXIS_LABEL_ATTRIBUTE);
Double value = Double.parseDouble(rangeCrosshairElement.getAttribute(CROSSHAIR_VALUE_ATTRIBUTE));
Float width = Float.parseFloat(rangeCrosshairElement.getAttribute(CROSSHAIR_WIDTH_ATTRIBUTE));
LineStyle style = LineStyle.valueOf(rangeCrosshairElement.getAttribute(CROSSHAIR_STYLE_ATTRIBUTE));
for (int k=0; k<rangeCrosshairElement.getChildNodes().getLength(); k++) {
Node colorNode = rangeCrosshairElement.getChildNodes().item(k);
if (colorNode.getNodeName().equals(CROSSHAIR_COLOR_ELEMENT)) {
Element colorElement = (Element) colorNode;
int r = Integer.parseInt(colorElement.getAttribute(CROSSHAIR_COLOR_R_ATTRIBUTE));
int g = Integer.parseInt(colorElement.getAttribute(CROSSHAIR_COLOR_G_ATTRIBUTE));
int b = Integer.parseInt(colorElement.getAttribute(CROSSHAIR_COLOR_B_ATTRIBUTE));
Color color = new Color(r, g, b);
line.getFormat().setColor(color);
}
}
line.setValue(value);
line.getFormat().setWidth(width);
line.getFormat().setStyle(style);
// decide if crosshair is of the currently selected range axis or not
List<AxisParallelLineConfiguration> listOfLines = rangeAxisCrosshairLinesMap.get(rangeAxisLabel);
if (listOfLines == null) {
listOfLines = new LinkedList<AxisParallelLineConfiguration>();
}
listOfLines.add(line);
rangeAxisCrosshairLinesMap.put(rangeAxisLabel, listOfLines);
}
}
}
} catch (NumberFormatException e) {
LogService.getRoot().warning("Could not restore range axis crosshairs!");
}
} else if (setting.getNodeName().equals(CROSSHAIR_DOMAIN_TOP_ELEMENT)) {
try {
// load domain axis crosshairs
for (int j=0; j<setting.getChildNodes().getLength(); j++) {
Node domainCrosshairNode = setting.getChildNodes().item(j);
if (domainCrosshairNode instanceof Element) {
Element domainCrosshairElement = (Element) domainCrosshairNode;
if (domainCrosshairElement.getNodeName().equals(CROSSHAIR_DOMAIN_ELEMENT)) {
// load domain axis crosshair
AxisParallelLineConfiguration line = new AxisParallelLineConfiguration(1.0, false);
Double value = Double.parseDouble(domainCrosshairElement.getAttribute(CROSSHAIR_VALUE_ATTRIBUTE));
Float width = Float.parseFloat(domainCrosshairElement.getAttribute(CROSSHAIR_WIDTH_ATTRIBUTE));
LineStyle style = LineStyle.valueOf(domainCrosshairElement.getAttribute(CROSSHAIR_STYLE_ATTRIBUTE));
for (int k=0; k<domainCrosshairElement.getChildNodes().getLength(); k++) {
Node colorNode = domainCrosshairElement.getChildNodes().item(k);
if (colorNode.getNodeName().equals(CROSSHAIR_COLOR_ELEMENT)) {
Element colorElement = (Element) colorNode;
int r = Integer.parseInt(colorElement.getAttribute(CROSSHAIR_COLOR_R_ATTRIBUTE));
int g = Integer.parseInt(colorElement.getAttribute(CROSSHAIR_COLOR_G_ATTRIBUTE));
int b = Integer.parseInt(colorElement.getAttribute(CROSSHAIR_COLOR_B_ATTRIBUTE));
Color color = new Color(r, g, b);
line.getFormat().setColor(color);
}
}
line.setValue(value);
line.getFormat().setWidth(width);
line.getFormat().setStyle(style);
// add to DomainConfigManager
plotInstance.getMasterPlotConfiguration().getDomainConfigManager().getCrosshairLines().addLine(line);
}
}
}
} catch (NumberFormatException e) {
LogService.getRoot().warning("Could not restore domain axis crosshairs!");
}
} else if (setting.getNodeName().equals(PlotterStyleProvider.STYLE_ELEMENT)) {
styleProvider.loadFromXML(setting);
}
}
}
suspendUpdates = false;
updatePlotConfiguration();
}
}