Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8824 Factors and Data Columns #8907

Merged
merged 4 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions Models/Graph/GraphPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,16 @@ public static List<SimulationDescription> FindSimulationDescriptions(IModel mode
{
// Find a parent that heads the scope that we're going to graph
IModel parent = FindParent(model);
if (parent is Simulation && parent.Parent is Experiment)
throw new Exception("Graph scope is incorrect if placed under a Simulation in an Experiment. It should be a child of the Experiment instead.");

List<SimulationDescription> simulationDescriptions = null;
do
{
List<SimulationDescription> simulationDescriptions = new List<SimulationDescription>();
while (simulationDescriptions.Count == 0 && parent != null) {
// Create a list of all simulation/zone objects that we're going to graph.
simulationDescriptions = GetSimulationDescriptionsUnderModel(parent);
parent = parent.Parent;
}
while (simulationDescriptions.Count == 0 && parent != null);

return simulationDescriptions;
}

Expand Down
52 changes: 29 additions & 23 deletions Models/Graph/SeriesDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -278,56 +278,62 @@ public void ReadData(DataTable data, List<SimulationDescription> simulationDescr
GetDataFromModels();
else
{
var fieldsThatExist = DataTableUtilities.GetColumnNames(data).ToList();
List<string> columnNames = DataTableUtilities.GetColumnNames(data).ToList();
List<string> simulationNames = new List<string>();

// If we have descriptors, then use them to filter the data for this series.
List<string> simulationNameFilter = new List<string>(); ;
IEnumerable<SimulationDescription> simulationNamesWithDescriptors = new List<SimulationDescription>();
if (Descriptors != null)
{
foreach (var descriptor in Descriptors)
{
if (!fieldsThatExist.Contains(descriptor.Name))
//Get the name of each sim that has a matching descriptor to this graph
foreach (SimulationDescription sim in simulationDescriptions) {
bool matched = true;
foreach (SimulationDescription.Descriptor descriptor in Descriptors)
{
if (simulationNamesWithDescriptors.Any())
simulationNamesWithDescriptors = simulationNamesWithDescriptors.Where(s => s.HasDescriptor(descriptor));
else
simulationNamesWithDescriptors = simulationDescriptions.Where(sim => sim.HasDescriptor(descriptor));
if (!sim.HasDescriptor(descriptor))
{
matched = false;
}
else
{
//Remove this descriptor from column name so that it isn't used to filter again
if (descriptor.Name.CompareTo("Zone") != 0)
columnNames.Remove(descriptor.Name);
}
}
if (matched) {
simulationNames.Add(sim.Name);
}
}
if (simulationNamesWithDescriptors.Any())
simulationNameFilter = simulationNamesWithDescriptors.Select(s => s.Name).ToList();
// Incorporate our scope filter if we haven't limited filter to particular simulations.
if (!simulationNameFilter.Any() && InScopeSimulationNames != null)
simulationNameFilter = new List<string>(InScopeSimulationNames);
}
//if we don't have descriptors, get all sim names in scope instead
else if (InScopeSimulationNames != null)
simulationNameFilter = new List<string>(InScopeSimulationNames ?? Enumerable.Empty<string>());
simulationNames = new List<string>(InScopeSimulationNames ?? Enumerable.Empty<string>());

string filter = GetFilter(fieldsThatExist);
//Make a filter on matching columns that were sim descriptors (factors)
string filter = GetFilter(columnNames);

if (simulationNameFilter.Any())
//Add our matching sim ids to the filter
if (simulationNames.Any())
{
var simulationIds = reader.ToSimulationIDs(simulationNameFilter);
var simulationIds = reader.ToSimulationIDs(simulationNames);
var simulationIdsCSV = StringUtilities.Build(simulationIds, ",");
if (string.IsNullOrEmpty(simulationIdsCSV))
return;
if (fieldsThatExist.Contains("SimulationID"))
if (columnNames.Contains("SimulationID"))
filter = AddToFilter(filter, $"SimulationID in ({simulationIdsCSV})");
}

//cleanup filter
filter = filter?.Replace('\"', '\'');
filter = RemoveMiddleWildcards(filter);

//apply our filter to the data
View = new DataView(data);
try
{
View.RowFilter = filter;
}
catch (Exception ex)
{
//this will still cause a pause when running in debug mode, that is due to how visual studio
//works when an exception thrown by external code but is not handled by that external code.
throw new Exception("Filter cannot be parsed: " + ex.Message);
}

Expand Down
65 changes: 65 additions & 0 deletions Tests/UnitTests/Graph/SeriesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1573,6 +1573,71 @@ public void SeriesFromPredictedObservedAndMixOfSimulations()
Assert.AreEqual(definitions[0].SeriesDefinitions[0].Y as double[], new double[] { 1, 5 });
}

/// <summary>Create xy series definitions from predicted/observed table.</summary>
[Test]
public void SeriesFromPredictedObservedWithMissingObserved()
{
var folder = new Folder()
{
Name = "Folder",
Children = new List<IModel>()
{
new MockSimulationDescriptionGenerator(new List<Description>()
{
new Description("Sim1", "SimulationName", "Sim1", "Experiment", "Exp1"),
new Description("Sim2", "SimulationName", "Sim2", "Experiment", "Exp1"),
new Description("Sim3", "SimulationName", "Sim3", "Experiment", "Exp2"),
new Description("Sim4", "SimulationName", "Sim4", "Experiment", "Exp2")
}),
new Graph()
{
Children = new List<IModel>()
{
new Series()
{
Name = "Series1",
TableName = "Report",
XFieldName = "Predicted.Grain.Wt",
YFieldName = "Observed.Grain.Wt",
FactorToVaryColours = "Experiment",
FactorToVaryMarkers = "Experiment"
}
}
}
}
};
folder.ParentAllDescendants();

string data =
"CheckpointName SimulationName SimulationID Predicted.Grain.Wt Observed.Grain.Wt Experiment\r\n" +
" () () () () () ()\r\n" +
" Current Sim1 1 1 1 Exp1\r\n" +
" Current Sim2 2 2 5 null\r\n" +
" Current Sim3 3 3 8 Exp2\r\n" +
" Current Sim4 4 4 6 Exp2\r\n";

var reader = new TextStorageReader(data);

var graph = folder.Children[1] as Graph;
var page = new GraphPage();
page.Graphs.Add(graph);
var definitions = page.GetAllSeriesDefinitions(graph, reader, null);

Assert.AreEqual(definitions.Count, 1);
Assert.AreEqual(definitions[0].SeriesDefinitions.Count, 2);
Assert.AreEqual(definitions[0].SeriesDefinitions[0].Colour, ColourUtilities.Colours[0]);
Assert.AreEqual(definitions[0].SeriesDefinitions[0].Marker, MarkerType.FilledCircle);
Assert.AreEqual(definitions[0].SeriesDefinitions[0].Title, "Exp1");
Assert.AreEqual(definitions[0].SeriesDefinitions[0].X as double[], new double[] { 1, 2 });
Assert.AreEqual(definitions[0].SeriesDefinitions[0].Y as double[], new double[] { 1, 5 });

Assert.AreEqual(definitions[0].SeriesDefinitions[1].Colour, ColourUtilities.Colours[1]);
Assert.AreEqual(definitions[0].SeriesDefinitions[1].Marker, MarkerType.FilledCircle);
Assert.AreEqual(definitions[0].SeriesDefinitions[1].Title, "Exp2");
Assert.AreEqual(definitions[0].SeriesDefinitions[1].X as double[], new double[] { 3, 4 });
Assert.AreEqual(definitions[0].SeriesDefinitions[1].Y as double[], new double[] { 8, 6 });
}

/// <summary>Create xy series definitions from predicted/observed table with error bars.</summary>
[Test]
public void SeriesWithErrorBars()
Expand Down