/// <summary> /// Checks whether the given axis tips and bases are both nearer to each other /// than a predefined border value. /// </summary> /// <param name="axisA"></param> /// <param name="axisB"></param> /// <returns>If they are near enough to span a MetaVis.</returns> public static bool CheckIfNearEnough(AxisPair axes) { var tipA = axes.A.GetAxisTipGlobal(); var baseA = axes.A.GetAxisBaseGlobal(); var tipB = axes.B.GetAxisTipGlobal(); var baseB = axes.B.GetAxisBaseGlobal(); if (((baseA - baseB).magnitude < triggerMetaVisDistance && (tipA - tipB).magnitude < triggerMetaVisDistance) || ((baseA - tipB).magnitude < triggerMetaVisDistance && (tipA - baseB).magnitude < triggerMetaVisDistance)) { if (Vector3.Angle(axes.A.GetAxisDirectionGlobal(), axes.B.GetAxisDirectionGlobal()) < 100) { return(true); } else { return(false); } } else { return(false); } }
public override AETV GenerateHeatmap3D(int dataSetID, string[] variables, AxisPair axes, bool duplicateAxes) { var mVis = new GameObject(); var comp = mVis.AddComponent <ETV2DScatterPlot>(); return(comp); }
public override AETV SpanMetaVisScatterplot2D(AxisPair axes, int dataSetID, bool duplicateAxes) { var mVis = new GameObject(); var comp = mVis.AddComponent <ETV2DScatterPlot>(); return(comp); }
public override AETV SpanMetaVisFlexibleLinedAxes(AxisPair axes, int dataSetID) { var mVis = new GameObject(); var comp = mVis.AddComponent <ETV2DScatterPlot>(); return(comp); }
public override AETV SpanMetaVisFor(AxisPair axes, int dataSetID, out MetaVisType type) { var o = new GameObject("Dummy MetaVis"); type = MetaVisType.FLEXIBLE_LINKED_AXES; return(o.AddComponent <NullETV>()); }
public float3 AtAngle(float angle, AxisPair axis) { //float3 n = (Quaternion.AngleAxis(angle, normal) * normalize(cross(normal, dir))) * radius; float3 n = mul(Unity.Mathematics.quaternion.AxisAngle(normal, angle / 0.0174532924f), normalize(cross(normal, dir))) * radius; return(float3(center.x + n.x, center.y + n.y, center.z + n.z)); }
public static Vector2 ToVector2(this Vector3 vector, AxisPair pair) { switch (pair) { case AxisPair.XY: return(vector); case AxisPair.XZ: return(new Vector2(vector.x, vector.z)); case AxisPair.YX: return(new Vector2(vector.y, vector.x)); case AxisPair.YZ: return(new Vector2(vector.y, vector.z)); case AxisPair.ZX: return(new Vector2(vector.z, vector.x)); case AxisPair.ZY: return(new Vector2(vector.z, vector.y)); default: Debug.LogError("Error, enum never read !"); return(vector); } }
// ........................................................................ Explicit Methods public void Init(AETV etv, AxisPair axes, int dsID) { metaVisualization = etv; spanningAxes = axes; dataSetID = dsID; initialized = true; FindShadowAxes(); Observe(axes.A); Observe(axes.B); }
/// <summary> /// (HELPER-MEHTOD) /// Are all preconditions met, to span up a meta-visualization? /// </summary> private bool MetaVisShouldBeCreated(AxisPair axes, out int dataSetID) { bool createIt = true; var mvisCombos = new MetaVisByAttributesAndETV(axes); createIt &= !usedCombinations.Contains(axes); createIt &= !usedCombinationsByAttributeAndETV.Contains(mvisCombos); createIt &= !axes.A.Base().Equals(axes.B.Base()); // not component of the same etv createIt &= !axes.A.attributeName.Equals(axes.B.attributeName); // do not represent the same attribute createIt &= CheckIfNearEnough(axes); // are close enought to each other createIt &= CheckIfCompatible(axes, out dataSetID); // are compatible and from the same data set return(createIt); }
public override AETV GenerateHeatmap3D(int dataSetID, string[] variables, AxisPair axes, bool duplicateAxes) { try { // Create Meta-Visualization var data = dataProvider.dataSets[dataSetID]; var plnt = Services.MetaVisFactory(); // Rotate and translate Meta-Visualization to match spanning axes // look in direction of cross product var up = Vector3.Cross( axes.A.GetAxisDirectionGlobal(), axes.B.GetAxisDirectionGlobal()); var angle = Vector3.SignedAngle(axes.A.GetAxisDirectionGlobal(), axes.B.GetAxisDirectionGlobal(), up); string[] vars = new string[2]; if (angle > 0) { vars[0] = variables[1]; vars[1] = variables[0]; } else { vars[0] = variables[0]; vars[1] = variables[1]; } var mVis = plnt.CreateMetaHeatmap3D(data, vars, true, 1, 1); RotateAndScaleCorrectly(mVis, new AAxis[] { axes.A, axes.B }); return(mVis); } catch (Exception e) // Handle potential failures { Debug.Log("Creation of requested MetaVis for variables " + variables + " failed."); Debug.LogError(e.Message); Debug.LogError(e.StackTrace); var o = new GameObject("Creation Failed"); return(o.AddComponent <ETV3DFlexiblePCP>()); } }
public override AETV SpanMetaVisFor(AxisPair axes, int dataSetID, out MetaVisType type) { // calculate distance between their origins var originDist = Vector3.Distance(axes.A.GetAxisBaseGlobal(), axes.B.GetAxisBaseGlobal()); // use existing axes (if origins are very close to each other), or create duplicates? var createDuplicates = (originDist > .2f); // Which metavisualization will do? switch (type = WhichMetaVis(axes, dataSetID)) { case MetaVisType.SCATTERPLOT_2D: return(SpanMetaVisScatterplot2D(axes, dataSetID, createDuplicates)); case MetaVisType.HEATMAP: return(SpanMetaVisHeatmap3D(axes, dataSetID, createDuplicates)); default: return(SpanMetaVisImmersiveAxis(axes, dataSetID)); } }
// .................................................................... Controller Methods public override bool CheckIfCompatible(AxisPair axes, out int dataSetID) { if (axes.A.stats.name == axes.B.stats.name) { //Debug.LogWarning("Given axes represent the same dimension and can't span a useful MetaVis."); dataSetID = -1; return(false); } if (axes.A.Equals(axes.B)) { //Debug.LogWarning("Given axes belong to the same visualization and are not connected by MetaVis'."); dataSetID = -1; return(false); } // Check every available Data Set for (int id = 0; id < dataProvider.dataSets.Length; id++) { var data = dataProvider.dataSets[id]; bool existsA = data.attIDbyNAME.ContainsKey(axes.A.stats.name); bool existsB = data.attIDbyNAME.ContainsKey(axes.B.stats.name); // If both variables exist in the same data set if (existsA && existsB) { bool correctLoMA = data.TypeOf(axes.A.stats.name) == axes.A.stats.type; bool correctLoMB = data.TypeOf(axes.B.stats.name) == axes.B.stats.type; if (existsA && existsB && correctLoMA && correctLoMB) { dataSetID = id; return(true); } } } dataSetID = -1; return(false); }
public bool RuleApplies(AAxis[] constellation) { if (constellation.Length != 2) { return(false); } else { var axes = new AxisPair(constellation[0], constellation[1]); var angle = Vector3.Angle(axes.A.GetAxisDirectionGlobal(), axes.B.GetAxisDirectionGlobal()); var orthogonalCase = (Mathf.Abs(angle - 90) < 5); var lomA = axes.A.stats.type; var lomB = axes.B.stats.type; var bothCategorical = (lomA == LoM.NOMINAL || lomA == LoM.ORDINAL) && (lomB == LoM.NOMINAL || lomB == LoM.ORDINAL); return(orthogonalCase && !bothCategorical); } }
/// <summary> /// Checks, which meta-visualization form would be appropriate /// for the given axes. /// /// For example the following MetaVis' are appropriate: /// /// | Axis constellation | MetaVis | /// +-------------------------------------------------------------------+-------------------------------+ /// | two arbitrarily constellated axes | immersive axes | /// | two arbitrarily constellated axes in the same layer | FLA | /// | two orthogonal constellated numerical axes in the same layer | scatterplot | /// | two orthogonal constellated categorical axes in the same layer | height map / 3D bar chart | /// </summary> /// <param name="axisA">first axis</param> /// <param name="axisB">second axis</param> /// <param name="dataSetID">data set ID of them</param> /// <returns>appropriate meta-visualization form</returns> public static MetaVisType WhichMetaVis(AxisPair axes, int dataSetID) { // Which MetaVis is defined by the implicit combination grammar? // ............................................ IMPLICIT GRAMMAR RULES // orthogonal case - 3 axes: scatterplot 3D // TODO - if enough time var constellation = new AAxis[] { axes.A, axes.B }; if (MikadoIRuleScatterplot2D.I.RuleApplies(constellation)) { return(MetaVisType.SCATTERPLOT_2D); } else if (MikadoIRuleHeatMap.I.RuleApplies(constellation)) { return(MetaVisType.HEATMAP); } else { return(MetaVisType.IMMERSIVE_AXES); } }
/// <summary> /// Generates an immersive axis meta-visualization between the given axes of /// the given data set. /// </summary> /// <param name="axisA">first axis</param> /// <param name="axisB">secon axis</param> /// <param name="dataSetID">data set ID of them</param> /// <returns>new immersive axes meta-visualization</returns> public abstract AETV SpanMetaVisImmersiveAxis(AxisPair pair, int dataSetID);
/// <summary> /// Generates a Flexible Linked Axes visualization between the given axes /// of the given data set. /// </summary> /// <param name="axisA">first axis</param> /// <param name="axisB">second axis</param> /// <param name="dataSetID">data set id of them</param> /// <returns>new FLA meta-visualization</returns> public abstract AETV SpanMetaVisFlexibleLinedAxes(AxisPair pair, int dataSetID);
public override AETV GenerateImmersiveAxes(int dataSetID, string[] variables, AxisPair axes) { var o = new GameObject("Dummy immersive axes"); return(o.AddComponent <ETV3DFlexiblePCP>()); }
public override bool CheckIfCompatible(AxisPair axes, out int dataSetID) { dataSetID = 0; return(false); }
public override AETV GenerateFlexibleLinkedAxes(int dataSetID, string[] variables, AxisPair axes) { var mVis = new GameObject(); var comp = mVis.AddComponent <ETV2DScatterPlot>(); return(comp); }
/// <summary> /// Generates a two dimensional scatterplot visualization between the /// given axes of the given data set. If axes origin's do not touch, /// axes will get duplicated and made perfectly orthogonal. /// </summary> /// <param name="axisA">first axis</param> /// <param name="axisB">second axis</param> /// <param name="dataSetID">data set ID of them</param> /// <param name="duplicateAxes">if axes should be ducplicated, because they do not touch</param> /// <returns>new 2d scatterplot meta-visualization</returns> public abstract AETV SpanMetaVisScatterplot2D(AxisPair pair, int dataSetID, bool duplicateAxes);
/// <summary> /// (HELPER METHOD) /// </summary> /// <param name="dataSetID"></param> /// <param name="variables"></param> /// <param name="axisA"></param> /// <param name="axisB"></param> /// <param name="duplicateAxes"></param> /// <returns></returns> public abstract AETV GenerateScatterplot2D(int dataSetID, string[] variables, AxisPair pair, bool duplicateAxes);
/// <summary> /// Generates a three dimensional heat map / bar chart, representing the relative /// distribution of samples according to the given axes. /// </summary> /// <param name="axisA">first axis</param> /// <param name="axisB">second axis</param> /// <param name="dataSetID">data set ID of them</param> /// <param name="duplicateAxes">if axes should be ducplicated</param> /// <returns>new 3d histogramm meta-visualization</returns> public abstract AETV SpanMetaVisHeatmap3D(AxisPair pair, int dataSetID, bool duplicateAxes);
public override AETV SpanMetaVisImmersiveAxis(AxisPair axes, int dataSetID) { var o = new GameObject("Dummy MetaVis Immersive Axis"); return(o.AddComponent <ETV3DFlexiblePCP>()); }
/// <summary> /// Removes the given axis from the list of permanently observed axes. /// Use this, when destroying or disabling a visualization. /// </summary> /// <param name="axis"></param> /// <summary> /// Generate a metavisualization between the given axes. /// </summary> /// <param name="axisA"></param> /// <param name="axisB"></param> /// <returns>A new metavisualization</returns> public abstract AETV SpanMetaVisFor(AxisPair pair, int dataSetID, out MetaVisType type);
/// <summary> /// Frees combination for new meta-visualizations. /// </summary> /// <param name="key"></param> public abstract void ReleaseCombination(AxisPair key);
/////////////////////////////////////////////////////////////////////////////////////////// // ........................................................................ MetaVis FACTORY /// <summary> /// Generates a 2D Parallel Coordinates Plot for n attributes. /// </summary> /// <param name="dataSetID"></param> /// <param name="variables">Attributes to be present in the PCP.</param> /// <returns>GameObject containing the anchored visualization.</returns> public abstract AETV GenerateImmersiveAxes(int dataSetID, string[] variables, AxisPair pair);
/// <summary> /// Checks for a dataset which contains both represented attributes and /// returns it's ID. /// Not compatible if they belong to the same ETV /// </summary> /// <param name="axisA"></param> /// <param name="axisB"></param> /// <returns>Whether such a dataset exists</returns> public abstract bool CheckIfCompatible(AxisPair axisPair, out int dataSetID);
public override void ReleaseCombination(AxisPair key) { // Do nothing }
/// <summary> /// (HELPER METHOD) /// </summary> /// <param name="dataSetID"></param> /// <param name="variables"></param> /// <param name="axisA"></param> /// <param name="axisB"></param> /// <param name="duplicateAxes"></param> /// <returns></returns> public abstract AETV GenerateHeatmap3D(int dataSetID, string[] variables, AxisPair pair, bool duplicateAxes);
/// <summary> /// (HELPER METHOD) /// </summary> /// <param name="dataSetID"></param> /// <param name="variables"></param> /// <param name="axisA"></param> /// <param name="axisB"></param> /// <returns></returns> public abstract AETV GenerateFlexibleLinkedAxes(int dataSetID, string[] variables, AxisPair pair);