<commit_before>/*
 * JaamSim Discrete Event Simulation
 * Copyright (C) 2009-2012 Ausenco Engineering Canada Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU 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 General Public License for more details.
 */
package com.sandwell.JavaSimulation3D;


import java.util.ArrayList;

import com.jaamsim.events.ProcessTarget;
import com.jaamsim.input.FormatInput;
import com.jaamsim.input.OutputListInput;
import com.jaamsim.input.ValueInput;
import com.jaamsim.input.ValueListInput;
import com.jaamsim.math.Color4d;
import com.jaamsim.math.Vec3d;
import com.jaamsim.ui.FrameBox;
import com.jaamsim.units.DimensionlessUnit;
import com.jaamsim.units.TimeUnit;
import com.jaamsim.units.Unit;
import com.jaamsim.units.UserSpecifiedUnit;
import com.sandwell.JavaSimulation.ColorListInput;
import com.sandwell.JavaSimulation.ColourInput;
import com.sandwell.JavaSimulation.DoubleListInput;
import com.sandwell.JavaSimulation.DoubleVector;
import com.sandwell.JavaSimulation.EntityInput;
import com.sandwell.JavaSimulation.Input;
import com.sandwell.JavaSimulation.InputErrorException;
import com.sandwell.JavaSimulation.IntegerInput;
import com.sandwell.JavaSimulation.Keyword;
import com.sandwell.JavaSimulation.Process;
import com.sandwell.JavaSimulation.StringInput;
import com.jaamsim.input.OutputHandle;

public class Graph extends DisplayEntity  {

	/**
	 * A struct containing all the information pertaining to a specific series
	 */
	public static class SeriesInfo {
		public double[] values;
		public int numPoints; // The first point to draw from the start (used to be confusingly called index)
		public int removedPoints; // The number of points to draw for entities that have been removed
		public OutputHandle out; // The source of the data for the series
		public boolean isRemoved = false; // Is this line slated for removal (entity is dead)
		public double lineWidth;
		public Color4d lineColour;
	}

	protected final ArrayList<SeriesInfo> primarySeries;
	protected final ArrayList<SeriesInfo> secondarySeries;

	private Class<? extends Unit> dataUnitType;          // unit type for the graphed lines plotted against the y-axis
	private Class<? extends Unit> secondaryDataUnitType;  // unit type for the graphed lines plotted against the secondary y-axis

	// Size and position of the graph area (excluding the titles, labels, etc.) scaled to the unit cube for the DisplayModel
	protected Vec3d graphSize;   // graph size
	protected Vec3d graphOrigin; // bottom left position of the graph area,
	protected Vec3d graphCenter; // Center point of the graph area

	static int ENTITY_ONLY = 0;
	static int PARAMETER_ONLY = 1;
	static int ENTITY_PARAMETER = 2;

	// Data category

	@Keyword(description = "The number of data points that can be displayed on the graph.\n" +
			" This parameter determines the resolution of the graph.",
	         example = "Graph1 NumberOfPoints { 200 }")
	protected final IntegerInput numberOfPoints;

	@Keyword(description = "One or more sources of data to be graphed on the primary y-axis.\n" +
			"Each source is graphed as a separate line and is specified by an Entity and its Output.",
     example = "Graph1 DataSource { { Entity-1 Output-1 } { Entity-2 Output-2 } }")
	protected final OutputListInput<Double> dataSource;

	@Keyword(description = "A list of colors for the line series to be displayed.\n" +
			"Each color can be specified by either a color keyword or an RGB value.\n" +
			"For multiple lines, each color must be enclosed in braces.\n" +
			"If only one color is provided, it is used for all the lines.",
	         example = "Graph1 LineColors { { red } { green } }")
	protected final ColorListInput lineColorsList;

	@Keyword(description = "A list of line widths (in pixels) for the line series to be displayed.\n" +
			"If only one line width is provided, it is used for all the lines.",
	         example = "Graph1 LineWidths { 2 1 }")
	protected final DoubleListInput lineWidths;

	@Keyword(description = "One or more sources of data to be graphed on the secondary y-axis.\n" +
			"Each source is graphed as a separate line and is specified by an Entity and its Output.",
     example = "Graph1 SecondaryDataSource { { Entity-1 Output-1 } { Entity-2 Output-2 } }")
	protected final OutputListInput<Double> secondaryDataSource;

	@Keyword(description = "A list of colors for the secondary line series to be displayed.\n" +
			"Each color can be specified by either a color keyword or an RGB value.\n" +
			"For multiple lines, each color must be enclosed in braces.\n" +
			"If only one color is provided, it is used for all the lines.",
	         example = "Graph1 SecondaryLineColors { { red } { green } }")
	protected final ColorListInput secondaryLineColorsList;

	@Keyword(description = "A list of line widths (in pixels) for the seconardy line series to be displayed.\n" +
			"If only one line width is provided, it is used for all the lines.",
	         example = "Graph1 SecondaryLineWidths { 2 1 }")
	protected final DoubleListInput secondaryLineWidths;

	// X-Axis category

	@Keyword(description = "The time unit to be used for the x-axis.",
	         example = "Graph1 XAxisUnit { h }")
	private final EntityInput<TimeUnit> xAxisUnit;

	@Keyword(description = "The start time for the x-axis relative to the present time.\n" +
			"The present time is 0 for this axis.",
	         example = "Graph1 StartTime { -48 h }")
	protected final ValueInput startTime;

	@Keyword(description = "The end time for the x-axis relative to the present time.\n" +
			"The present time is 0 for this axis.",
	         example = "Graph1 EndTime { 8 h }")
	protected final ValueInput endTime;

	@Keyword(description = "The time increment between the tick marks on the x-axis.",
	         example = "Graph1 TimeInterval { 8 h }")
	private final ValueInput timeInterval;

	@Keyword(description = "The Java format to be used for the tick mark values on the x-axis.\n" +
			"For example, the format %.1fs would dispaly the value 5 as 5.0s.",
	         example = "Graph1 XAxisLabelFormat { %.1fs }")
	private final FormatInput xAxisLabelFormat;

	@Keyword(description = "A list of time values between StartTime and EndTime where vertical gridlines are inserted.",
	         example = "Graph1 XLines { -48 -40 -32 -24 -16 -8 0 h }")
	private final ValueListInput xLines;

	@Keyword(description = "The color of the vertical gridlines (or a list corresponding to the colour of each " +
	                "gridline defined in XLines), defined using a colour keyword or RGB values.",
	         example = "Graph1 XLinesColor { gray76 }")
	private final ColorListInput xLinesColor;

	// Y-Axis category

	@Keyword(description = "Title of the y-axis, enclosed in single quotes, rotated by 90 degrees counter-clockwise.",
	         example = "Graph1 YAxisTitle { 'Water Height (m)' }")
	private final StringInput yAxisTitle;

	@Keyword(description = "The unit to be used for the y-axis.\n" +
			"The unit chosen must be consistent with the unit type for the DataSource value,\n" +
			"i.e. if the data has units of distance, then unit must be a distance unit such as meters.",
	         example = "Graph1 YAxisUnit { t/h }")
	private final EntityInput<? extends Unit> yAxisUnit;

	@Keyword(description = "The minimum value for the y-axis.",
	         example = "Graph1 YAxisStart { 0 t/h }")
	private final ValueInput yAxisStart;

	@Keyword(description = "The maximum value for the y-axis.",
	         example = "Graph1 YAxisEnd { 5 t/h }")
	private final ValueInput yAxisEnd;

	@Keyword(description = "The interval between y-axis labels.",
	         example = "Graph1 YAxisInterval { 1 t/h }")
	private final ValueInput yAxisInterval;

	@Keyword(description  = "The Java format to be used for the tick mark values on the y-axis.\n" +
			"For example, the format %.1f would dispaly the value 5 as 5.0.",
	         example = "Graph1 YAxisLabelFormat { %.1f }")
	private final FormatInput yAxisLabelFormat;

	@Keyword(description = "A list of values at which to insert horizontal gridlines.",
	         example ="Graph1 YLines { 0  0.5  1  1.5  2  2.5  3  t/h }")
	private final ValueListInput yLines;

	@Keyword(description = "The colour of the horizontal gridlines (or a list corresponding to the colour of each " +
                    "gridline defined in YLines), defined using a colour keyword or RGB values.",
	         example = "Graph1 YLinesColor { gray76 }")
	private final ColorListInput yLinesColor;

	// Secondary Y-Axis category

	@Keyword(description = "Title of the secondary y-axis, enclosed in single quotes, rotated by 90 degrees clockwise.",
	         example = "Graph1 SecondaryYAxisTitle { 'Water Height (m)' }")
	private final StringInput secondaryYAxisTitle;

	@Keyword(description = "The unit to be used for the secondary y-axis.\n" +
			"The unit chosen must be consistent with the unit type for the DataSource value,\n" +
			"i.e. if the data has units of distance, then unit must be a distance unit such as meters.",
	         example = "Graph1 SecondaryYAxisUnit { m }")
	private final EntityInput<? extends Unit> secondaryYAxisUnit;

	@Keyword(description = "The minimum value for the secondary y-axis.",
	         example = "Graph1 SecondaryYAxisStart { 0 m }")
	private final ValueInput secondaryYAxisStart;

	@Keyword(description = "The maximum value for the secondary y-axis.",
	         example = "Graph1 SecondaryYAxisEnd { 5 m }")
	private final ValueInput secondaryYAxisEnd;

	@Keyword(description = "The interval between secondary y-axis labels.",
	         example = "Graph1 SecondaryYAxisInterval { 1 m }")
	private final ValueInput secondaryYAxisInterval;

	@Keyword(description  = "The Java format to be used for the tick mark values on the secondary y-axis.\n" +
			"For example, the format %.1f would dispaly the value 5 as 5.0.",
	         example = "Graph1 SecondaryYAxisLabelFormat { %.1f }")
	private final FormatInput secondaryYAxisLabelFormat;

	// Layout category

	@Keyword(description= "Text for the graph title, enclosed in single quotes if it contains spaces.",
	         example = "Graph1 Title { 'Title of the Graph' }")
	private final StringInput title;

	@Keyword(description = "The text height for the graph title.",
	         example = "Graph1 TitleTextHeight { 0.05 }")
	private final ValueInput titleTextHeight;

	@Keyword(description = "The text height for the y-axis title.\n" +
			"Expressed as a fraction of the total graph height.",
	         example = "Graph1 YAxisTitleTextHeight { 0.05 }")
	private final ValueInput yAxisTitleTextHeight;

	@Keyword(description = "The text height for both x- and y-axis labels.\n" +
			"Expressed as a fraction of the total graph height.",
	         example = "Graph1 LabelTextHeight { 0.025 }")
	private final ValueInput labelTextHeight;

	@Keyword(description = "The gap between the title and top of the graph.\n" +
			"Expressed as a fraction of the total graph height.",
	         example = "Graph1 TitleGap { 0.025 }")
	private final ValueInput titleGap;

	@Keyword(description = "The gap between the x-axis labels and the x-axis.\n" +
			"Expressed as a fraction of the total graph height.",
	         example = "Graph1 XAxisLabelGap { 0.025 }")
	private final ValueInput xAxisLabelGap;

	@Keyword(description = "The gap between the y-axis and its labels.\n" +
			"Expressed as a fraction of the total graph height.",
	         example = "Graph1 YAxisLabelGap { 0.025 }")
	private final ValueInput yAxisLabelGap;

	@Keyword(description = "The gap between the y-axis title and the y-axis labels.\n" +
			"Expressed as a fraction of the total graph height.",
	         example = "Graph1 yAxisTitleGap { 0.025 }")
	private final ValueInput yAxisTitleGap;

	@Keyword(description = "The margin between the top of the graph and the top of the graph object.\n" +
			"Expressed as a fraction of the total graph height." +
	                "side of the graph.",
	         example = "Graph1 TopMargin { 0.10 }")
	private final ValueInput topMargin;

	@Keyword(description = "The margin between the bottom of the graph and the bottom of the graph object.\n" +
	                "Expressed as a fraction of the total graph height.",
             example = "Graph1 BottomMargin { 0.10 }")
	private final ValueInput bottomMargin;

	@Keyword(description = "The margin between the left side of the graph and the left side of the graph object.\n" +
	                "Expressed as a fraction of the total graph height.",
	         example = "Graph1 LeftMargin { 0.20 }")
	private final ValueInput leftMargin;

	@Keyword(description = "The margin between the right side of the graph and the right side of the graph object.\n" +
	                "Expressed as a fraction of the total graph height.",
	         example = "Graph1 RightMargin { 0.20 }")
	private final ValueInput rightMargin;

	@Keyword(description = "The text model to be used for the graph title.\n" +
			"Determines the font, color, and style (bold, italics) for the text.",
	         example = "Graph1 TitleTextModel { TextModelDefault }")
	protected final EntityInput<TextModel> titleTextModel;

	@Keyword(description = "The text model to be used for the axis titles (x-axis, y-axis, and secondary y-axis).\n" +
			"Determines the font, color, and style (bold, italics) for the text.",
	         example = "Graph1 AxisTitleTextModel { TextModelDefault }")
	protected final EntityInput<TextModel> axisTitleTextModel;

	@Keyword(description = "The text model to be used for the numbers next to the tick marks on each axis" +
			" (x-axis, y-axis, and secondary y-axis).\n" +
			"Determines the font, color, and style (bold, italics) for the text.",
	         example = "Graph1 LabelTextModel { TextModelDefault }")
	protected final EntityInput<TextModel> labelTextModel;

	@Keyword(description = "The colour of the graph background, defined by a color keyword or RGB values.",
	         example = "Graph1 GraphColor { floralwhite }")
	private final ColourInput graphColor;

	@Keyword(description = "The color for the outer pane background, defined using a colour keyword or RGB values.",
	         example = "Graph1 BackgroundColor { floralwhite }")
	private final ColourInput backgroundColor;

	@Keyword(description = "The color of the graph border, defined using a colour keyword or RGB values.",
	         example = "Graph1 BorderColor { red }")
	private final ColourInput borderColor;

	{
		// Data category

		numberOfPoints = new IntegerInput("NumberOfPoints", "Data", 100);
		numberOfPoints.setValidRange(0, Integer.MAX_VALUE);
		this.addInput(numberOfPoints, true);

		dataSource = new OutputListInput<Double>(Double.class, "DataSource", "Data", null);<commit_msg>JS: Use "color" instead of "colour" for Graph keyword descriptions<commit_after>/*
 * JaamSim Discrete Event Simulation
 * Copyright (C) 2009-2012 Ausenco Engineering Canada Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU 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 General Public License for more details.
 */
package com.sandwell.JavaSimulation3D;


import java.util.ArrayList;

import com.jaamsim.DisplayModels.DisplayModel;
import com.jaamsim.DisplayModels.TextModel;
import com.jaamsim.events.ProcessTarget;
import com.jaamsim.input.FormatInput;
import com.jaamsim.input.OutputListInput;
import com.jaamsim.input.ValueInput;
import com.jaamsim.input.ValueListInput;
import com.jaamsim.math.Color4d;
import com.jaamsim.math.Vec3d;
import com.jaamsim.ui.FrameBox;
import com.jaamsim.units.DimensionlessUnit;
import com.jaamsim.units.TimeUnit;
import com.jaamsim.units.Unit;
import com.jaamsim.units.UserSpecifiedUnit;
import com.sandwell.JavaSimulation.ColorListInput;
import com.sandwell.JavaSimulation.ColourInput;
import com.sandwell.JavaSimulation.DoubleListInput;
import com.sandwell.JavaSimulation.DoubleVector;
import com.sandwell.JavaSimulation.EntityInput;
import com.sandwell.JavaSimulation.Input;
import com.sandwell.JavaSimulation.InputErrorException;
import com.sandwell.JavaSimulation.IntegerInput;
import com.sandwell.JavaSimulation.Keyword;
import com.sandwell.JavaSimulation.Process;
import com.sandwell.JavaSimulation.StringInput;
import com.jaamsim.input.OutputHandle;

public class Graph extends DisplayEntity  {

	/**
	 * A struct containing all the information pertaining to a specific series
	 */
	public static class SeriesInfo {
		public double[] values;
		public int numPoints; // The first point to draw from the start (used to be confusingly called index)
		public int removedPoints; // The number of points to draw for entities that have been removed
		public OutputHandle out; // The source of the data for the series
		public boolean isRemoved = false; // Is this line slated for removal (entity is dead)
		public double lineWidth;
		public Color4d lineColour;
	}

	protected final ArrayList<SeriesInfo> primarySeries;
	protected final ArrayList<SeriesInfo> secondarySeries;

	private Class<? extends Unit> dataUnitType;          // unit type for the graphed lines plotted against the y-axis
	private Class<? extends Unit> secondaryDataUnitType;  // unit type for the graphed lines plotted against the secondary y-axis

	// Size and position of the graph area (excluding the titles, labels, etc.) scaled to the unit cube for the DisplayModel
	protected Vec3d graphSize;   // graph size
	protected Vec3d graphOrigin; // bottom left position of the graph area,
	protected Vec3d graphCenter; // Center point of the graph area

	static int ENTITY_ONLY = 0;
	static int PARAMETER_ONLY = 1;
	static int ENTITY_PARAMETER = 2;

	// Data category

	@Keyword(description = "The number of data points that can be displayed on the graph.\n" +
			" This parameter determines the resolution of the graph.",
	         example = "Graph1 NumberOfPoints { 200 }")
	protected final IntegerInput numberOfPoints;

	@Keyword(description = "One or more sources of data to be graphed on the primary y-axis.\n" +
			"Each source is graphed as a separate line and is specified by an Entity and its Output.",
     example = "Graph1 DataSource { { Entity-1 Output-1 } { Entity-2 Output-2 } }")
	protected final OutputListInput<Double> dataSource;

	@Keyword(description = "A list of colors for the line series to be displayed.\n" +
			"Each color can be specified by either a color keyword or an RGB value.\n" +
			"For multiple lines, each color must be enclosed in braces.\n" +
			"If only one color is provided, it is used for all the lines.",
	         example = "Graph1 LineColors { { red } { green } }")
	protected final ColorListInput lineColorsList;

	@Keyword(description = "A list of line widths (in pixels) for the line series to be displayed.\n" +
			"If only one line width is provided, it is used for all the lines.",
	         example = "Graph1 LineWidths { 2 1 }")
	protected final DoubleListInput lineWidths;

	@Keyword(description = "One or more sources of data to be graphed on the secondary y-axis.\n" +
			"Each source is graphed as a separate line and is specified by an Entity and its Output.",
     example = "Graph1 SecondaryDataSource { { Entity-1 Output-1 } { Entity-2 Output-2 } }")
	protected final OutputListInput<Double> secondaryDataSource;

	@Keyword(description = "A list of colors for the secondary line series to be displayed.\n" +
			"Each color can be specified by either a color keyword or an RGB value.\n" +
			"For multiple lines, each color must be enclosed in braces.\n" +
			"If only one color is provided, it is used for all the lines.",
	         example = "Graph1 SecondaryLineColors { { red } { green } }")
	protected final ColorListInput secondaryLineColorsList;

	@Keyword(description = "A list of line widths (in pixels) for the seconardy line series to be displayed.\n" +
			"If only one line width is provided, it is used for all the lines.",
	         example = "Graph1 SecondaryLineWidths { 2 1 }")
	protected final DoubleListInput secondaryLineWidths;

	// X-Axis category

	@Keyword(description = "The time unit to be used for the x-axis.",
	         example = "Graph1 XAxisUnit { h }")
	private final EntityInput<TimeUnit> xAxisUnit;

	@Keyword(description = "The start time for the x-axis relative to the present time.\n" +
			"The present time is 0 for this axis.",
	         example = "Graph1 StartTime { -48 h }")
	protected final ValueInput startTime;

	@Keyword(description = "The end time for the x-axis relative to the present time.\n" +
			"The present time is 0 for this axis.",
	         example = "Graph1 EndTime { 8 h }")
	protected final ValueInput endTime;

	@Keyword(description = "The time increment between the tick marks on the x-axis.",
	         example = "Graph1 TimeInterval { 8 h }")
	private final ValueInput timeInterval;

	@Keyword(description = "The Java format to be used for the tick mark values on the x-axis.\n" +
			"For example, the format %.1fs would dispaly the value 5 as 5.0s.",
	         example = "Graph1 XAxisLabelFormat { %.1fs }")
	private final FormatInput xAxisLabelFormat;

	@Keyword(description = "A list of time values between StartTime and EndTime where vertical gridlines are inserted.",
	         example = "Graph1 XLines { -48 -40 -32 -24 -16 -8 0 h }")
	private final ValueListInput xLines;

	@Keyword(description = "The color of the vertical gridlines (or a list corresponding to the colour of each " +
	                "gridline defined in XLines), defined using a colour keyword or RGB values.",
	         example = "Graph1 XLinesColor { gray76 }")
	private final ColorListInput xLinesColor;

	// Y-Axis category

	@Keyword(description = "Title of the y-axis, enclosed in single quotes, rotated by 90 degrees counter-clockwise.",
	         example = "Graph1 YAxisTitle { 'Water Height (m)' }")
	private final StringInput yAxisTitle;

	@Keyword(description = "The unit to be used for the y-axis.\n" +
			"The unit chosen must be consistent with the unit type for the DataSource value,\n" +
			"i.e. if the data has units of distance, then unit must be a distance unit such as meters.",
	         example = "Graph1 YAxisUnit { t/h }")
	private final EntityInput<? extends Unit> yAxisUnit;

	@Keyword(description = "The minimum value for the y-axis.",
	         example = "Graph1 YAxisStart { 0 t/h }")
	private final ValueInput yAxisStart;

	@Keyword(description = "The maximum value for the y-axis.",
	         example = "Graph1 YAxisEnd { 5 t/h }")
	private final ValueInput yAxisEnd;

	@Keyword(description = "The interval between y-axis labels.",
	         example = "Graph1 YAxisInterval { 1 t/h }")
	private final ValueInput yAxisInterval;

	@Keyword(description  = "The Java format to be used for the tick mark values on the y-axis.\n" +
			"For example, the format %.1f would dispaly the value 5 as 5.0.",
	         example = "Graph1 YAxisLabelFormat { %.1f }")
	private final FormatInput yAxisLabelFormat;

	@Keyword(description = "A list of values at which to insert horizontal gridlines.",
	         example ="Graph1 YLines { 0  0.5  1  1.5  2  2.5  3  t/h }")
	private final ValueListInput yLines;

	@Keyword(description = "The colour of the horizontal gridlines (or a list corresponding to the colour of each " +
                    "gridline defined in YLines), defined using a colour keyword or RGB values.",
	         example = "Graph1 YLinesColor { gray76 }")
	private final ColorListInput yLinesColor;

	// Secondary Y-Axis category

	@Keyword(description = "Title of the secondary y-axis, enclosed in single quotes, rotated by 90 degrees clockwise.",
	         example = "Graph1 SecondaryYAxisTitle { 'Water Height (m)' }")
	private final StringInput secondaryYAxisTitle;

	@Keyword(description = "The unit to be used for the secondary y-axis.\n" +
			"The unit chosen must be consistent with the unit type for the DataSource value,\n" +
			"i.e. if the data has units of distance, then unit must be a distance unit such as meters.",
	         example = "Graph1 SecondaryYAxisUnit { m }")
	private final EntityInput<? extends Unit> secondaryYAxisUnit;

	@Keyword(description = "The minimum value for the secondary y-axis.",
	         example = "Graph1 SecondaryYAxisStart { 0 m }")
	private final ValueInput secondaryYAxisStart;

	@Keyword(description = "The maximum value for the secondary y-axis.",
	         example = "Graph1 SecondaryYAxisEnd { 5 m }")
	private final ValueInput secondaryYAxisEnd;

	@Keyword(description = "The interval between secondary y-axis labels.",
	         example = "Graph1 SecondaryYAxisInterval { 1 m }")
	private final ValueInput secondaryYAxisInterval;

	@Keyword(description  = "The Java format to be used for the tick mark values on the secondary y-axis.\n" +
			"For example, the format %.1f would dispaly the value 5 as 5.0.",
	         example = "Graph1 SecondaryYAxisLabelFormat { %.1f }")
	private final FormatInput secondaryYAxisLabelFormat;

	// Layout category

	@Keyword(description= "Text for the graph title, enclosed in single quotes if it contains spaces.",
	         example = "Graph1 Title { 'Title of the Graph' }")
	private final StringInput title;

	@Keyword(description = "The text height for the graph title.",
	         example = "Graph1 TitleTextHeight { 0.05 }")
	private final ValueInput titleTextHeight;

	@Keyword(description = "The text height for the y-axis title.\n" +
			"Expressed as a fraction of the total graph height.",
	         example = "Graph1 YAxisTitleTextHeight { 0.05 }")
	private final ValueInput yAxisTitleTextHeight;

	@Keyword(description = "The text height for both x- and y-axis labels.\n" +
			"Expressed as a fraction of the total graph height.",
	         example = "Graph1 LabelTextHeight { 0.025 }")
	private final ValueInput labelTextHeight;

	@Keyword(description = "The gap between the title and top of the graph.\n" +
			"Expressed as a fraction of the total graph height.",
	         example = "Graph1 TitleGap { 0.025 }")
	private final ValueInput titleGap;

	@Keyword(description = "The gap between the x-axis labels and the x-axis.\n" +
			"Expressed as a fraction of the total graph height.",
	         example = "Graph1 XAxisLabelGap { 0.025 }")
	private final ValueInput xAxisLabelGap;

	@Keyword(description = "The gap between the y-axis and its labels.\n" +
			"Expressed as a fraction of the total graph height.",
	         example = "Graph1 YAxisLabelGap { 0.025 }")
	private final ValueInput yAxisLabelGap;

	@Keyword(description = "The gap between the y-axis title and the y-axis labels.\n" +
			"Expressed as a fraction of the total graph height.",
	         example = "Graph1 yAxisTitleGap { 0.025 }")
	private final ValueInput yAxisTitleGap;

	@Keyword(description = "The margin between the top of the graph and the top of the graph object.\n" +
			"Expressed as a fraction of the total graph height." +
	                "side of the graph.",
	         example = "Graph1 TopMargin { 0.10 }")
	private final ValueInput topMargin;

	@Keyword(description = "The margin between the bottom of the graph and the bottom of the graph object.\n" +
	                "Expressed as a fraction of the total graph height.",
             example = "Graph1 BottomMargin { 0.10 }")
	private final ValueInput bottomMargin;

	@Keyword(description = "The margin between the left side of the graph and the left side of the graph object.\n" +
	                "Expressed as a fraction of the total graph height.",
	         example = "Graph1 LeftMargin { 0.20 }")
	private final ValueInput leftMargin;

	@Keyword(description = "The margin between the right side of the graph and the right side of the graph object.\n" +
	                "Expressed as a fraction of the total graph height.",
	         example = "Graph1 RightMargin { 0.20 }")
	private final ValueInput rightMargin;

	@Keyword(description = "The text model to be used for the graph title.\n" +
			"Determines the font, color, and style (bold, italics) for the text.",
	         example = "Graph1 TitleTextModel { TextModelDefault }")
	protected final EntityInput<TextModel> titleTextModel;

	@Keyword(description = "The text model to be used for the axis titles (x-axis, y-axis, and secondary y-axis).\n" +
			"Determines the font, color, and style (bold, italics) for the text.",
	         example = "Graph1 AxisTitleTextModel { TextModelDefault }")
	protected final EntityInput<TextModel> axisTitleTextModel;

	@Keyword(description = "The text model to be used for the numbers next to the tick marks on each axis" +
			" (x-axis, y-axis, and secondary y-axis).\n" +
			"Determines the font, color, and style (bold, italics) for the text.",
	         example = "Graph1 LabelTextModel { TextModelDefault }")
	protected final EntityInput<TextModel> labelTextModel;

	@Keyword(description = "The color of the graph background, defined by a color keyword or an RGB value.",
	         example = "Graph1 GraphColor { floralwhite }")
	private final ColourInput graphColor;

	@Keyword(description = "The color for the outer pane background, defined using a color keyword or an RGB value.",
	         example = "Graph1 BackgroundColor { floralwhite }")
	private final ColourInput backgroundColor;

	@Keyword(description = "The color of the graph border, defined using a color keyword or an RGB value.",
	         example = "Graph1 BorderColor { red }")
	private final ColourInput borderColor;

	{
		// Data category

		numberOfPoints = new IntegerInput("NumberOfPoints", "Data", 100);
		numberOfPoints.setValidRange(0, Integer.MAX_VALUE);
		this.addInput(numberOfPoints, true);

		dataSource = new OutputListInput<Double>(Double.class, "DataSource", "Data", null);
{'fraction_non_alphanumeric': 0.08400171634155197, 'fraction_numerical': 0.011816351453939333, 'mean_word_length': 3.6504988488104373, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4260155', 'n_tokens_mistral': 8773, 'n_tokens_neox': 8263, 'n_words': 3527}