/// <summary> /// Creates a new AggregateGraph for the given dataset (<paramref name="cata"/>) /// </summary> /// <param name="cata"></param> /// <param name="name">The name to give the graph</param> /// <param name="dimension1">The first dimension e.g. pass only one dimension to create a bar chart</param> /// <param name="isAxis">True if <paramref name="dimension1"/> should be created as a axis (creates a line chart)</param> /// <param name="dimension2">Optional second dimension to create (this will be the pivot column)</param> private AggregateConfiguration CreateGraph(Catalogue cata, string name, string dimension1, bool isAxis, string dimension2) { var ac = new AggregateConfiguration(_repos.CatalogueRepository, cata, name); ac.CountSQL = "count(*) as NumberOfRecords"; ac.SaveToDatabase(); ac.IsExtractable = true; var mainDimension = ac.AddDimension(GetExtractionInformation(cata, dimension1)); var otherDimension = string.IsNullOrWhiteSpace(dimension2) ? null : ac.AddDimension(GetExtractionInformation(cata, dimension2)); if (isAxis) { var axis = new AggregateContinuousDateAxis(_repos.CatalogueRepository, mainDimension); axis.StartDate = "'1970-01-01'"; axis.AxisIncrement = FAnsi.Discovery.QuerySyntax.Aggregation.AxisIncrement.Year; axis.SaveToDatabase(); } if (otherDimension != null) { ac.PivotOnDimensionID = otherDimension.ID; ac.SaveToDatabase(); } return(ac); }
private void ddAxisDimension_SelectedIndexChanged(object sender, EventArgs e) { if (isRefreshing) { return; } var selectedDimension = ddAxisDimension.SelectedItem as AggregateDimension; if (selectedDimension == null) { return; } //is there already an axis? if so keep the old start/end dates var existing = _aggregate.GetAxisIfAny(); //create a new one var axis = new AggregateContinuousDateAxis(Activator.RepositoryLocator.CatalogueRepository, selectedDimension); axis.AxisIncrement = AxisIncrement.Month; //copy over old values of start/end/increment if (existing != null && existing.AggregateDimension_ID != selectedDimension.ID) { axis.StartDate = existing.StartDate; axis.EndDate = existing.EndDate; axis.AxisIncrement = existing.AxisIncrement; existing.DeleteInDatabase(); } axis.SaveToDatabase(); PublishToSelfOnly(); }
private void SetupLineGraph(DataTable dt, AggregateContinuousDateAxis axis, string countColumnName, int boundsWidth, int boundsHeight) { graphView.AxisY.Text = countColumnName; graphView.GraphColor = Driver.MakeAttribute(Color.White, Color.Black); var xIncrement = 1f / (boundsWidth / (float)dt.Rows.Count); graphView.MarginBottom = 2; graphView.AxisX.Increment = xIncrement * 10; graphView.AxisX.ShowLabelsEvery = 1; graphView.AxisX.Text = axis.AxisIncrement.ToString(); graphView.AxisX.LabelGetter = (v) => { var x = (int)v.Value; return(x < 0 || x >= dt.Rows.Count ? "" : dt.Rows[x][0].ToString()); }; float minY = 0; float maxY = 1; var colors = GetColors(dt.Columns.Count - 1); for (int i = 1; i < dt.Columns.Count; i++) { var series = new PathAnnotation() { LineColor = colors[i - 1], BeforeSeries = true }; int row = 0; foreach (DataRow dr in dt.Rows) { // Treat nulls as 0 var yVal = dr[i] == DBNull.Value ? 0 : (float)Convert.ToDouble(dr[i]); minY = Math.Min(minY, yVal); maxY = Math.Max(maxY, yVal); series.Points.Add(new PointF(row++, yVal)); } graphView.Annotations.Add(series); } var yIncrement = 1 / ((boundsHeight - graphView.MarginBottom) / (maxY - minY)); graphView.CellSize = new PointF(xIncrement, yIncrement); graphView.AxisY.LabelGetter = (v) => FormatValue(v.Value, minY, maxY); graphView.MarginLeft = (uint)(Math.Max(FormatValue(maxY, minY, maxY).Length, FormatValue(minY, minY, maxY).Length)) + 1; var legend = GetLegend(dt, boundsWidth, boundsHeight); for (int i = 1; i < dt.Columns.Count; i++) { legend.AddEntry(new GraphCellToRender('.', colors[i - 1]), dt.Columns[i].ColumnName); } }
private void PopulateGraphResults(DataTable dt, string countColumnName, AggregateContinuousDateAxis axis) { // if (chart1.Legends.Count == 0) // chart1.Legends.Add(new Legend()); // clear any lingering settings graphView.Reset(); // Work out how much screen real estate we have var boundsWidth = graphView.Bounds.Width; var boundsHeight = graphView.Bounds.Height; if (boundsWidth == 0) { boundsWidth = TabView.Bounds.Width - 4; } if (boundsHeight == 0) { boundsHeight = TabView.Bounds.Height - 4; } var titleWidth = aggregate.Name.Sum(c => Rune.ColumnWidth(c)); var titleStartX = (boundsWidth / 2) - (titleWidth / 2); var title = new TextAnnotation() { ScreenPosition = new Point(titleStartX, 0), Text = aggregate.Name, BeforeSeries = false }; graphView.Annotations.Add(title); // if no time axis then we have a regular bar chart if (axis == null) { if (dt.Columns.Count == 2) { SetupBarSeries(dt, countColumnName, boundsWidth, boundsHeight); } else { SetupMultiBarSeries(dt, countColumnName, boundsWidth, boundsHeight); } } else { SetupLineGraph(dt, axis, countColumnName, boundsWidth, boundsHeight); } }
private AggregateConfiguration SetupAggregateWithAxis(DatabaseType type, ExtractionInformation[] extractionInformations, ICatalogue catalogue, out AggregateDimension axisDimension) { var dateDimension = extractionInformations.Single( e => e.GetRuntimeName().Equals("EventDate", StringComparison.CurrentCultureIgnoreCase)); var configuration = new AggregateConfiguration(CatalogueRepository, catalogue, "GroupBy_Category"); axisDimension = new AggregateDimension(CatalogueRepository, dateDimension, configuration); var axis = new AggregateContinuousDateAxis(CatalogueRepository, axisDimension); axis.StartDate = "'2000-01-01'"; axis.AxisIncrement = AxisIncrement.Year; axis.SaveToDatabase(); return(configuration); }
private void PopulateGraphResults(QueryTimeColumn countColumn, AggregateContinuousDateAxis axis) { bool haveSetSource = false; if (chart1.Legends.Count == 0) { chart1.Legends.Add(new Legend()); } //last column is always the X axis, then for each column before it add a series with Y values coming from that column for (int i = 0; i < _dt.Columns.Count - 1; i++) { int index = i; if (!haveSetSource) { try { dataGridView1.DataSource = _dt; lblCannotLoadData.Visible = false; } catch (Exception e) { lblCannotLoadData.Visible = true; lblCannotLoadData.Text = "Could not load data table:" + e.Message; dataGridView1.DataSource = null; } chart1.DataSource = _dt; haveSetSource = true; } chart1.ChartAreas[0].AxisX.IsMarginVisible = false; chart1.ChartAreas[0].AxisY.IsMarginVisible = false; if (axis != null) { switch (axis.AxisIncrement) { case AxisIncrement.Day: chart1.ChartAreas[0].AxisX.Title = "Day"; if (_dt.Rows.Count <= 370) { //by two months chart1.ChartAreas[0].AxisX.MinorGrid.Interval = 7; chart1.ChartAreas[0].AxisX.MajorGrid.Interval = 14; chart1.ChartAreas[0].AxisX.Interval = 14; } else { chart1.ChartAreas[0].AxisX.MajorGrid.Interval = 28; chart1.ChartAreas[0].AxisX.MinorGrid.Interval = 7; chart1.ChartAreas[0].AxisX.Interval = 28; } chart1.ChartAreas[0].AxisX.MinorGrid.LineWidth = 1; chart1.ChartAreas[0].AxisX.MinorGrid.LineDashStyle = ChartDashStyle.Dot; chart1.ChartAreas[0].AxisX.MinorGrid.Enabled = true; break; case AxisIncrement.Month: //x axis is the number of rows in the data table chart1.ChartAreas[0].AxisX.Title = "Month"; //if it is less than or equal to ~3 years at once - with if (_dt.Rows.Count <= 40) { //by month chart1.ChartAreas[0].AxisX.MinorGrid.Interval = 1; chart1.ChartAreas[0].AxisX.MajorGrid.Interval = 3; chart1.ChartAreas[0].AxisX.Interval = 1; } else { //by year chart1.ChartAreas[0].AxisX.MinorGrid.Interval = 6; chart1.ChartAreas[0].AxisX.MajorGrid.Interval = 12; chart1.ChartAreas[0].AxisX.Interval = 12; } chart1.ChartAreas[0].AxisX.MinorGrid.LineWidth = 1; chart1.ChartAreas[0].AxisX.MinorGrid.LineDashStyle = ChartDashStyle.Dot; chart1.ChartAreas[0].AxisX.MinorGrid.Enabled = true; break; case AxisIncrement.Year: chart1.ChartAreas[0].AxisX.Title = "Year"; if (_dt.Rows.Count <= 10) { chart1.ChartAreas[0].AxisX.MinorGrid.Interval = 1; chart1.ChartAreas[0].AxisX.MajorGrid.Interval = 1; chart1.ChartAreas[0].AxisX.Interval = 1; } else { chart1.ChartAreas[0].AxisX.MinorGrid.Interval = 1; chart1.ChartAreas[0].AxisX.MajorGrid.Interval = 5; chart1.ChartAreas[0].AxisX.Interval = 5; } chart1.ChartAreas[0].AxisX.MinorGrid.LineWidth = 1; chart1.ChartAreas[0].AxisX.MinorGrid.LineDashStyle = ChartDashStyle.Dot; chart1.ChartAreas[0].AxisX.MinorGrid.Enabled = true; break; case AxisIncrement.Quarter: //x axis is the number of rows in the data table chart1.ChartAreas[0].AxisX.Title = "Quarter"; //if it is less than or equal to ~3 years at once - with if (_dt.Rows.Count <= 12) { //by quarter chart1.ChartAreas[0].AxisX.MinorGrid.Interval = 1; chart1.ChartAreas[0].AxisX.MajorGrid.Interval = 4; chart1.ChartAreas[0].AxisX.Interval = 4; } else { //by year chart1.ChartAreas[0].AxisX.MinorGrid.Interval = 1; chart1.ChartAreas[0].AxisX.MajorGrid.Interval = 16; chart1.ChartAreas[0].AxisX.Interval = 16; } chart1.ChartAreas[0].AxisX.MinorGrid.LineWidth = 1; chart1.ChartAreas[0].AxisX.MinorGrid.LineDashStyle = ChartDashStyle.Dot; chart1.ChartAreas[0].AxisX.MinorGrid.Enabled = true; break; default: throw new ArgumentOutOfRangeException(); } } else { chart1.ChartAreas[0] = new ChartArea(); //reset it chart1.ChartAreas[0].AxisX.Title = _dt.Columns[0].ColumnName; } //Set the Y axis title if (countColumn != null) { try { chart1.ChartAreas[0].AxisY.Title = countColumn.IColumn.GetRuntimeName(); } catch (Exception) { chart1.ChartAreas[0].AxisY.Title = "Count"; //sometimes you can't get a runtime name e.g. it is count(*) with no alias } } chart1.ChartAreas[0].AxisY.MinorGrid.Enabled = true; chart1.ChartAreas[0].AxisY.MinorGrid.LineDashStyle = ChartDashStyle.Dot; chart1.ChartAreas[0].AxisY.LabelStyle.Format = "{0:#,#}"; //avoid buffer overun if (index > chart1.Series.Count - 1) { chart1.Series.Add(new Series()); } chart1.Series[index].XValueMember = _dt.Columns[0].ColumnName; chart1.Series[index].YValueMembers = _dt.Columns[index + 1].ColumnName; if (axis != null) { chart1.Series[index].ChartType = SeriesChartType.Line; //alternate in rotating style the various lines on the graph chart1.Series[index].BorderDashStyle = StyleList[index % StyleList.Length]; chart1.Series[index].BorderWidth = 2; } else { chart1.Series[index].ChartType = SeriesChartType.Column; if (_dt.Columns[0].DataType == typeof(decimal) || _dt.Columns[0].DataType == typeof(int)) { //by year chart1.ChartAreas[0].AxisX.IntervalAutoMode = IntervalAutoMode.FixedCount; } else { chart1.ChartAreas[0].AxisX.Interval = 1; chart1.ChartAreas[0].AxisX.LabelAutoFitMinFontSize = 8; } } //name series based on column 3 or the aggregate name chart1.Series[index].Name = _dt.Columns[index + 1].ColumnName; } //don't show legend if theres only the one series if (chart1.Series.Count == 1) { chart1.Legends.Clear(); } lblLoadStage.Text = "Data Binding Chart (" + _dt.Columns.Count + " columns)"; lblLoadStage.Refresh(); int cells = _dt.Columns.Count * _dt.Rows.Count; bool abandon = false; if (cells > MAXIMUM_CELLS_BEFORE_WARNING) { if (Silent) { throw new Exception($"Aborting data binding because there were {cells} cells in the graph data table"); } else { abandon = !Activator.YesNo($"Data Table has {String.Format("{0:n0}", cells)} cells. Are you sure you want to attempt to graph it?", "Render Graph?"); } } if (!abandon) { chart1.DataBind(); chart1.Visible = true; } pbLoading.Visible = false; llCancel.Visible = false; lblLoadStage.Visible = false; //set publish enabledness to the enabledness of btnCache.Enabled = Activator.RepositoryLocator.CatalogueRepository.GetServerDefaults().GetDefaultFor(PermissableDefaults.WebServiceQueryCachingServer_ID) != null; btnClearFromCache.Enabled = false; //Make publish button enabledness be dependant on cache if (btnCache.Enabled) { //let them clear if there is a query caching server and the manager has cached results already btnClearFromCache.Enabled = GetCacheManager() .GetLatestResultsTableUnsafe(AggregateConfiguration, AggregateOperation.ExtractableAggregateResults) != null; } SetToolbarButtonsEnabled(true); }
private void LoadGraph() { try { int timeout = 10000; while (!IsHandleCreated && timeout > 0) { timeout -= 100; Thread.Sleep(100); if (timeout <= 0) { throw new TimeoutException( "Window Handle was not created on AggregateGraph control after 10 seconds of calling LoadGraph!"); } } this.Invoke(new MethodInvoker(() => { lblLoadStage.Visible = true; lblLoadStage.Text = "Generating Query..."; })); AggregateContinuousDateAxis axis = AggregateConfiguration.GetAxisIfAny(); AggregateBuilder builder = GetQueryBuilder(AggregateConfiguration); UpdateQueryViewerScreenWithQuery(builder.SQL); var countColumn = builder.SelectColumns.FirstOrDefault(c => c.IColumn is AggregateCountColumn); var server = AggregateConfiguration.Catalogue.GetDistinctLiveDatabaseServer( DataAccessContext.InternalDataProcessing, true); this.Invoke(new MethodInvoker(() => { lblLoadStage.Text = "Connecting To Server..."; })); using (var con = server.GetConnection()) { con.Open(); _cmd = server.GetCommand(builder.SQL, con); _cmd.CommandTimeout = Timeout; _dt = new DataTable(); this.Invoke(new MethodInvoker(() => { lblLoadStage.Text = "Executing Query..."; })); DbDataAdapter adapter = server.GetDataAdapter(_cmd); adapter.Fill(_dt); _cmd = null; //trim all leading/trailing whitespace from column foreach (DataColumn c in _dt.Columns) { c.ColumnName = c.ColumnName.Trim(); } if (_dt.Rows.Count == 0) { throw new Exception("Query Returned No Rows"); } //setup the heatmap if there is a pivot if (_dt.Columns.Count > 2 && AggregateConfiguration.PivotOnDimensionID != null) { this.Invoke(new MethodInvoker(() => heatmapUI.SetDataTable(_dt))); } else { this.Invoke(new MethodInvoker(() => heatmapUI.Clear())); } if (GraphTableRetrieved != null) { GraphTableRetrieved(this, _dt); } if (_dt.Columns.Count < 2) { throw new NotSupportedException("Aggregates must have 2 columns at least"); } //Invoke onto main UI thread so we can setup the chart this.Invoke(new MethodInvoker(() => { PopulateGraphResults(countColumn, axis); Done = true; })); } Invoke(new MethodInvoker(() => { lblLoadStage.Text = "Crashed"; })); ShowHeatmapTab(heatmapUI.HasDataTable()); } catch (Exception e) { //don't bother if it is closing / closed if (IsDisposed) { return; } Crashed = true; Exception = e; ragSmiley1.SetVisible(true); ragSmiley1.Fatal(e); AbortLoadGraph(); SetToolbarButtonsEnabled(true); Done = true; } }
/// <summary> /// Populates _sql (SQL property) and resolves all parameters, filters containers etc. Basically Finalizes this query builder /// </summary> public void RegenerateSQL() { SelectColumns.Sort(); //things we discover below, set them all to default values again _pivotDimension = null; _axisAppliesToDimension = null; _axis = null; _isCohortIdentificationAggregate = false; ParameterManager.ClearNonGlobals(); if (_queryLevelParameterProvider != null) { ParameterManager.AddParametersFor(_queryLevelParameterProvider, ParameterLevel.QueryLevel); } TableInfo primary; TablesUsedInQuery = SqlQueryBuilderHelper.GetTablesUsedInQuery(this, out primary, _forceJoinsToTheseTables); var tables = _forceJoinsToTheseTables != null ? TablesUsedInQuery.Union(_forceJoinsToTheseTables).ToList() : TablesUsedInQuery; if (!tables.Any()) { throw new QueryBuildingException("No tables could be identified for the query. Try adding a column or a force join"); } //get the database language syntax based on the tables used in the query _syntaxHelper = SqlQueryBuilderHelper.GetSyntaxHelper(tables); //tell the count column what language it is if (_countColumn != null) { _isCohortIdentificationAggregate = _aggregateConfigurationIfAny != null && _aggregateConfigurationIfAny.IsCohortIdentificationAggregate; //if it is not a cic aggregate then make sure it has an alias e.g. count(*) AS MyCount. cic aggregates take extreme liberties with this field like passing in 'distinct chi' and '*' and other wacky stuff that is so not cool _countColumn.SetQuerySyntaxHelper(_syntaxHelper, !_isCohortIdentificationAggregate); } IAggregateHelper aggregateHelper = _syntaxHelper.AggregateHelper; if (_pivotID != -1) { try { _pivotDimension = SelectColumns.Single( qtc => qtc.IColumn is AggregateDimension && ((AggregateDimension)qtc.IColumn).ID == _pivotID); } catch (Exception e) { throw new QueryBuildingException("Problem occurred when trying to find PivotDimension ID " + _pivotID + " in SelectColumns list", e); } } foreach (AggregateDimension dimension in SelectColumns.Select(c => c.IColumn).Where(e => e is AggregateDimension)) { var availableAxis = dimension.AggregateContinuousDateAxis; if (availableAxis != null) { if (_axis != null) { throw new QueryBuildingException( "Multiple dimensions have an AggregateContinuousDateAxis within the same configuration (Dimensions " + _axisAppliesToDimension.GetRuntimeName() + " and " + dimension.GetRuntimeName() + ")"); } else { _axis = availableAxis; _axisAppliesToDimension = dimension; } } } if (_pivotDimension != null) { if (_pivotDimension.IColumn == _axisAppliesToDimension) { throw new QueryBuildingException("Column " + _pivotDimension.IColumn + " is both a PIVOT and has an AXIS configured on it, you cannot have both."); } } //work out all the filters Filters = SqlQueryBuilderHelper.GetAllFiltersUsedInContainerTreeRecursively(RootFilterContainer); //tell the manager about them ParameterManager.AddParametersFor(Filters); if (AggregateTopX != null) { SqlQueryBuilderHelper.HandleTopX(this, _syntaxHelper, AggregateTopX.TopX); } else { SqlQueryBuilderHelper.ClearTopX(this); } //if user wants to force join to some other tables that don't appear in the SELECT list, who are we to stop him! if (_forceJoinsToTheseTables != null) { foreach (TableInfo t in _forceJoinsToTheseTables) { if (!TablesUsedInQuery.Contains(t)) { TablesUsedInQuery.Add(t); ParameterManager.AddParametersFor(t); } //if user has force joined to a primary extraction table if (t.IsPrimaryExtractionTable) { if (primary == null) //we don't currently know the primary (i.e. none of the SELECT columns were from primary tables so use this table as primary) { primary = t; } else if (primary.ID == t.ID) //we know the primary already but it is the same table so thats fine { continue; } else { //this isn't fine throw new QueryBuildingException("You chose to FORCE a join to table " + t + " which is marked IsPrimaryExtractionTable but you have also selected a column called " + primary + " which is also an IsPrimaryExtractionTable (cannot have 2 different primary extraction tables)"); } } } } this.PrimaryExtractionTable = primary; SqlQueryBuilderHelper.FindLookups(this); JoinsUsedInQuery = SqlQueryBuilderHelper.FindRequiredJoins(this); var queryLines = new List <CustomLine>(); _sql = ""; ValidateDimensions(); //assuming we were not told to ignore the writing out of parameters! if (!DoNotWriteOutParameters) { foreach (ISqlParameter parameter in ParameterManager.GetFinalResolvedParametersList()) { queryLines.Add(new CustomLine(QueryBuilder.GetParameterDeclarationSQL(parameter), QueryComponent.VariableDeclaration)); } } CompileCustomLinesInStageAndAddToList(QueryComponent.VariableDeclaration, queryLines); //put the name in as SQL comments followed by the SQL e.g. the name of an AggregateConfiguration or whatever GetSelectSQL(queryLines); queryLines.Add(new CustomLine(SqlQueryBuilderHelper.GetFROMSQL(this), QueryComponent.FROM)); CompileCustomLinesInStageAndAddToList(QueryComponent.JoinInfoJoin, queryLines); queryLines.Add(new CustomLine(SqlQueryBuilderHelper.GetWHERESQL(this), QueryComponent.WHERE)); CompileCustomLinesInStageAndAddToList(QueryComponent.WHERE, queryLines); GetGroupBySQL(queryLines, aggregateHelper); queryLines = queryLines.Where(l => !string.IsNullOrWhiteSpace(l.Text)).ToList(); _sql = aggregateHelper.BuildAggregate(queryLines, _axis); }
public override void Execute() { base.Execute(); if (string.IsNullOrWhiteSpace(column) && !askAtRuntime) { aggregate.GetAxisIfAny()?.DeleteInDatabase(); } else { if (aggregate.GetAxisIfAny() != null) { throw new Exception($"Aggregate {aggregate} already has an axis"); } var opts = new AggregateBuilderOptionsFactory().Create(aggregate); AggregateDimension match = null; if (askAtRuntime) { var possible = aggregate.AggregateDimensions.Where(d => d.IsDate()).ToArray(); if (!possible.Any()) { throw new Exception($"There are no AggregateDimensions in {aggregate} that can be used as an axis (Dimensions must be Date Type)"); } match = (AggregateDimension)BasicActivator.SelectOne("Choose axis dimension", possible); if (match == null) { return; } } else { match = aggregate.AggregateDimensions.FirstOrDefault(a => string.Equals(column, a.ToString())); if (match == null) { throw new Exception($"Could not find AggregateDimension {column} in Aggregate {aggregate} so could not set it as an axis dimension. Try adding the column to the aggregate first"); } } if (!match.IsDate()) { throw new Exception($"AggregateDimension {match} is not a Date so cannot set it as an axis for Aggregate {aggregate}"); } var enable = opts.ShouldBeEnabled(AggregateEditorSection.AXIS, aggregate); if (!enable) { throw new Exception($"Current state of Aggregate {aggregate} does not support having an axis Dimension"); } var axis = new AggregateContinuousDateAxis(BasicActivator.RepositoryLocator.CatalogueRepository, match); axis.SaveToDatabase(); } Publish(aggregate); }