Trying to find workaround to some bar series issues

A forum dedicated to WPF version of LightningChart Ultimate.

Moderator: Queue Moderators

Post Reply
cwodarczyk82
Posts: 43
Joined: Mon Oct 19, 2015 2:50 am

Trying to find workaround to some bar series issues

Post by cwodarczyk82 » Wed Nov 18, 2015 6:45 pm

To whom it may concern...

I have been working on a workaround to some of the issues I have been having with bar series graphs, and feel like I have gotten as close as I can, but I can't nail down whatever the issue is that I am having... in the 6.5.1 release of the software there is a problem with having one x axis item have 2 bars, and another having 3 for example... not to dump a huge amount of code on here, but this is the algorithm I have come up with for doing this.... I tried to comment it the best I could....

Also, to reference the other outstanding issue is that the team I am working on doesn't want to upgrade to the latest version for several reasons, so that is why I am trying to find a workaround...

Code: Select all

        private void PlotEntries(List<StateTopResourcesDataEntry> entries, List<StateResourceType> excludedResources = null)
        {
            Chart.BeginUpdate();
            
            //Get XYview
            var chartView = Chart.ViewXY;

            // Clear all current bars on the plot
            chartView.BarSeries.Clear();

            // Group all bars together by location
            chartView.BarViewOptions.Grouping = BarsGrouping.ByLocation;
            chartView.BarViewOptions.BarSpacing = 0;

            // Clear the last set of custom ticks
            var axisX = chartView.XAxes[0];
            axisX.CustomTicks.Clear();

            //Get default y-axis and set the range.
            var axisY = chartView.YAxes[0];

            // Order the plots by state name
            var plotPoints = entries.OrderBy(e => e.StateName);

            // Grab all the states to get a unique state list
            var uniqueStates = plotPoints.Select(e => e.StateName);

            // Create the custom ticks based on the state names (these positions will be modified later below)
            // For now, just place them on the graph
            
            var plotCount = 0;
            foreach (var state in uniqueStates)
            {
                axisX.CustomTicks.Add(new CustomAxisTick {AxisValue = plotCount++, LabelText = state});
            }
            
            // Place the x axis labels at 90 degrees
            axisX.LabelsAngle = 90;
            // Has to be done so the custom ticks will redraw
            axisX.InvalidateCustomTicks();

            var allBars = new List<BarSeries>();

            var stateBarDictionary = new List<BarSeriesWithIndex>();

            var stateIndex = 0;
            // In order to support a different number of bars per x axis point, we need to add the items in a round-robin fashion...
            // That is, we need to add the plot point from item 1 first, then the first item from 2, then from 3, etc...
            // Then, we need to go back and plot the next item from 1, the next item from 2, etc... we keep doing this until we run
            // out of buckets
            foreach (var plotPoint in plotPoints)
            {
                // Each plot point represents the state containing its resources
                var barSeries = new List<BarSeries>();

                // Loop through the resources in each state...
                foreach (var resource in plotPoint.Resources)
                {
                    // In case there are excluded resources, don't apply them
                    if (null == excludedResources || !excludedResources.Contains(resource.ResourceType))
                    {
                        // Create the bar and tag it with the resource type for later
                        var bar = ItemFactory.CreateBarSeries(chartView, axisX, axisY);
                        bar.Tag = resource.ResourceType;
                        // This text dictates how the legend shows up
                        bar.Title.Text = resource.ResourceType.ToString();
                        // If this is already being shown, make sure it doesn't show up in the legend twice!
                        if (!_currentResourcesShown.Contains(resource.ResourceType))
                        {
                            bar.ShowInLegendBox = true;
                            _currentResourcesShown.Add(resource.ResourceType);
                        }
                        else
                        {
                            bar.ShowInLegendBox = false;
                        }
                        bar.BorderColor = Colors.DarkGray;
                        bar.BorderWidth = 1;
                        // Fill color based on resource type
                        switch (resource.ResourceType)
                        {
                            case StateResourceType.Banking:
                                bar.Fill = new Fill() {Color = Colors.Green};
                                break;
                            case StateResourceType.Logging:
                                bar.Fill = new Fill() {Color = Colors.DarkOliveGreen};
                                break;
                            case StateResourceType.Mining:
                                bar.Fill = new Fill() {Color = Colors.Goldenrod};
                                break;
                            case StateResourceType.Oil:
                                bar.Fill = new Fill() {Color = Colors.Black};
                                break;
                            case StateResourceType.Tech:
                                bar.Fill = new Fill() {Color = Colors.Crimson};
                                break;
                            case StateResourceType.Tourism:
                                bar.Fill = new Fill() {Color = Colors.DarkMagenta};
                                break;
                            default:
                                bar.Fill = new Fill() {Color = Colors.Transparent};
                                break;
                        }
                        // Find the custom tick associated with this item (the state's name)
                        var tick = axisX.CustomTicks.SingleOrDefault(t => t.LabelText == plotPoint.StateName);

                        // Create a bar for this specific item, giving it the location, text and values
                        if (tick != null)
                        {
                            bar.Values = new[]
                            {
                                new BarSeriesValue()
                                {
                                    Location = stateIndex,
                                    Text = resource.IncomeFrom.ToString(),
                                    Value = resource.IncomeFrom,
                                }
                            };
                            barSeries.Add(bar);
                        }
                    }
                }
                // Done adding bar values for all items in this state, add in bar series with index...
                if (barSeries.Count > 0)
                {
                    stateBarDictionary.Add(new BarSeriesWithIndex(barSeries));
                }
                ++stateIndex;
            }

            var keepGoing = true;
            var index = 0;
            var totalItems = stateBarDictionary.Count();
            while(totalItems > 0 && keepGoing)
            {
                // Get the item at the current index (0, 1, 2, ...)
                var item = stateBarDictionary[index];
                // Reset this for the check below (to see if all items have been exhausted)
                var itemCount = 0;
                // If the current item we are looking has exhausted all the bar series made for it, look for the next item that hasn't yet..
                while(item.CurrentIndex >= item.BarSeries.Count())
                {
                    // This means we have checked all items and they have all exhausted their bar series... exit out
                    if (itemCount == totalItems)
                    {
                        keepGoing = false;
                        break;
                    }
                    // Go to the next item and check to see if all items have been used in it...
                    index = (index + 1) % totalItems;
                    item = stateBarDictionary[index];
                    ++itemCount;
                }
                // True means we found an item in our bucket where we haven't added all the bars into the series
                if (keepGoing)
                {
                    // Add this bar next...
                    allBars.Add(item.BarSeries[item.CurrentIndex]);
                    // Next time we come to this item, we will add the next bar from it
                    item.CurrentIndex++;
                    index = (index + 1)%totalItems;
                }
            }

            // Add the bar series in the order it was created above... this is the workaround for Arction not working like it should
            allBars.ForEach(l => chartView.BarSeries.Add(l));

            // This will cause all the bars to regraph
            allBars.ForEach(l => l.InvalidateData());

            // Determine the ranges manually for the bar graphs
            DetermineGraphRanges(stateIndex);

            // Now, we have to space the bars correctly ourselves (something else Arction doesn't seem to do correctly)
            SpaceBars(stateIndex);

            // Now, we have to position our bars correctly ourselves (something else Arction doesn't seem to do correctly)
            PositionBarsCorrectly(stateIndex);
            Chart.ViewXY.LegendBox.SeriesTitleMouseClick += SeriesTitleClickHandler;
            Chart.ViewXY.LegendBox.CheckBoxStateChanged += CheckBoxStateChangedHandler;
            

            /*
            var chartView = Chart.ViewXY;
            var axisX = chartView.XAxes[0];
            var axisY = chartView.YAxes[0];

            chartView.BarViewOptions.Grouping = BarsGrouping.ByLocation;
            chartView.BarViewOptions.BarSpacing = 0;

            var bar = ItemFactory.CreateBarSeries(chartView, axisX, axisY);

            bar.Title.Text = "Dummy";
            bar.ShowInLegendBox = true;
            bar.Fill = new Fill() { Color = Colors.Green };
            bar.Values = new[]
                            {
                                new BarSeriesValue()
                                {
                                    Location = 1.0,
                                    Text = "1000",
                                    Value = 1000,
                                }
                            };

            chartView.BarSeries.Add(bar);*/

            Chart.EndUpdate();
        }

        private void DetermineGraphRanges(int currentStateCount)
        {
            // Find the bar spacing (in our case, bar spacing will be the spacing between groups of bars, not individual bars)
            var barSpacing = Chart.ViewXY.BarViewOptions.BarSpacing;

            // Find the minimum custom tick location
            var minimumCustomTickLocation = Chart.ViewXY.XAxes[0].CustomTicks.Min(ct => ct.AxisValue);

            // Find the maximum custom tick location
            var maximumCustomTickLocation = Chart.ViewXY.XAxes[0].CustomTicks.Max(ct => ct.AxisValue);

            // The min/max region we can draw in will take into account the bar spacing, so we give enough room on the left and right
            // of the chart
            var minScreenCoord =
                Chart.ViewXY.XAxes[0].ValueToCoord(minimumCustomTickLocation) - barSpacing;
            var maxScreenCoord =
                Chart.ViewXY.XAxes[0].ValueToCoord(maximumCustomTickLocation) + barSpacing;

            // We need to convert these values back to value points
            double minValueCoord;
            double maxValueCoord;

            if (Chart.ViewXY.XAxes[0].CoordToValue((int)minScreenCoord, out minValueCoord, false))
            {
                Chart.ViewXY.XAxes[0].Minimum = minValueCoord;
            }

            if (Chart.ViewXY.XAxes[0].CoordToValue((int)maxScreenCoord, out maxValueCoord, false))
            {
                Chart.ViewXY.XAxes[0].Maximum = maxValueCoord;
            }
        }

        private void SpaceBars(int currentStateCount)
        {
            // The min/max region we can draw in will take into account the bar spacing, so we give enough room on the left and right
            // of the chart
            var minScreenCoord =
                Chart.ViewXY.XAxes[0].ValueToCoord(Chart.ViewXY.XAxes[0].Minimum);
            var maxScreenCoord =
                Chart.ViewXY.XAxes[0].ValueToCoord(Chart.ViewXY.XAxes[0].Maximum);

            // Actual region we can draw in is this... the difference between the min and max screen coordinate
            // This would be for one bar, for instance
            var barWidth = (maxScreenCoord - minScreenCoord);

            // Find number of ticks graphed...
            var numberOfTicksGraphed = Chart.ViewXY.XAxes[0].CustomTicks.Count;

            // Find the bar spacing (in our case, bar spacing will be the spacing between groups of bars, not individual bars)
            var barSpacing = Chart.ViewXY.BarViewOptions.BarSpacing;

            // Take out the region we have for graphing based on the bar spacing and the number of items graphed...
            // We will use the spacing only between tick marks and groups of bars
            // Arction doesn't provide a way to space bars by grouping... we have to do this manually
            barWidth -= (barSpacing * (numberOfTicksGraphed - 1));

            // Count the total number of bars
            float barCount = Chart.ViewXY.BarSeries.Count(s => _currentResourcesShown.Contains((StateResourceType)(int)s.Tag));
            // Find what the bar width should be
            barWidth /= barCount;

            // Set all the bar widths
            foreach (var barSeries in Chart.ViewXY.BarSeries)
            {
                barSeries.BarThickness = (int)barWidth;
            }
        }

        private void PositionBarsCorrectly(int currentStateCount)
        {
            var barSpacing = Chart.ViewXY.BarViewOptions.BarSpacing;

            // Find current screen coordinate...
            var currentScreenCoordinate = Chart.ViewXY.XAxes[0].ValueToCoord(Chart.ViewXY.XAxes[0].Minimum) + barSpacing;

            // All bars are same thickness... just look at the first one
            var barThickness = Chart.ViewXY.BarSeries[0].BarThickness;

            // Figure out how many bars associated with the current x item... we can order the bar series by location
            foreach(var customTick in Chart.ViewXY.XAxes[0].CustomTicks)
            //for(int stateIndex = 0; stateIndex < currentStateCount; ++stateIndex)
            {
                var currentGrouping = Chart.ViewXY.BarSeries.Where(barSeries => Math.Abs(barSeries.Values[0].Location - customTick.AxisValue) < float.Epsilon).ToList();

                // Count number of items in this grouping...
                var count = currentGrouping.Count();

                // Total width of this region....
                float totalWidth = count*barThickness;

                // Find the middle of this region (the tick needs to go in the middle of the bar group)
                var correctBarLocation = currentScreenCoordinate + (totalWidth / 2);

                // Find end of this region in screen coordinates...
                currentScreenCoordinate += totalWidth;

                // Now, convert to value coordinate, and all items in this grouping will get updated to that position...
                var valueCoordinate = 0.0;

                if (Chart.ViewXY.XAxes[0].CoordToValue((int)correctBarLocation, out valueCoordinate, true))
                {
                    // Need to update the custom tick location first...
                    customTick.AxisValue = valueCoordinate;

                    // Update all the bar series to this location (there is only one value per series...)
                    foreach (var barSeries in currentGrouping)
                    {
                        barSeries.Values[0].Location = valueCoordinate;
                    }
                }

                // Move to the next beginning of the bar (which should be based on the bar spacing...
                currentScreenCoordinate += barSpacing;
            }
        }
However, even though I am specifically trying to place the bar graps where I want, I seem to be unable to keep the first and last bar graph series from being cutoff in the middle, and I can't seem to prevent the spacing that is going on between the groupings, even though I am not adding any spacing between the groups if you reference my code above... I know it's a bit of code to go through, and I guess I won't expect a response right away, but I am kind of stuck at this point.. I will keep playing with this in the meantime...

Here is a reference to the display I get using the code...

[img]
LatestBarSeries.PNG
LatestBarSeries.PNG (205.78 KiB) Viewed 10244 times
[/img]

Thanks for your time!

User avatar
ArctionPasi
Posts: 1367
Joined: Tue Mar 26, 2013 10:57 pm
Location: Finland
Contact:

Re: Trying to find workaround to some bar series issues

Post by ArctionPasi » Wed Nov 18, 2015 8:34 pm

Wasn't this discussed here: http://forum.arction.com/viewtopic.php?f=16&t=696

The support for uneven count of bar items per group was included in 6.5.5 and I spent several days to program that. Wasn't that a working solution? :|


If you want to stick with the old version, you may want to replace the BarSeries with Annotations. They support sizing and positioning in screen coordinates and axis values. And you can show the label in there. This approach needs some positioning calculation on your side.
LightningChart Support Team, PT

cwodarczyk82
Posts: 43
Joined: Mon Oct 19, 2015 2:50 am

Re: Trying to find workaround to some bar series issues

Post by cwodarczyk82 » Wed Nov 18, 2015 8:46 pm

Actually, it looks like we will be upgrading, so we will be able to take the 6.5.5 changes where I can have a different number of bars per graph... I just tried the .dll now, and it all works the way I would expect... so first off, thank you very much for releasing this so I can have a different number of bars per x value! :D


[img]
6.5.5.PNG
6.5.5.PNG (184.8 KiB) Viewed 10239 times
[/img]

However, I still have a question about dynamically making the bar widths depending on the number of bars currently being shown, kind of like how ByIndexFitWidth works (there is no ByLocationFitWidth)... so as you can see in the picture above, I am still not able to keep the beginning of the graph from hiding the first half of the first item and last half of the last item... I also can't seem to get rid of the bar spacing between groups...

I have been using breakpoints and checking the values in the variables and everything seems ok, so I am not sure what I am missing... like I said, I will keep looking into it, but in the meantime, any help would be appreciated! :)

Code: Select all

        protected override void PlotEntries(IEnumerable<StateTopResourcesDataEntry> entries)
        {
            using (new LightningChartUpdate(Chart))
            {
                //Get XYview
                var chartView = Chart.ViewXY;

                chartView.BarViewOptions.Grouping = BarsGrouping.ByLocation;
                chartView.BarViewOptions.BarSpacing = 0;
                //chartView.BarViewOptions.IndexGroupingFitSideMargins = 0;
                //chartView.BarViewOptions.IndexGroupingFitGroupDistance = 0;

                //Get default x-axis and set the range and ValueType
                var axisX = chartView.XAxes[0];
                axisX.CustomTicks.Clear();

                //Get default y-axis and set the range.
                var axisY = chartView.YAxes[0];

                var plotPoints = entries as IList<StateTopResourcesDataEntry> ?? entries.ToList();

                // Determine the custom ticks we need
                var orderedByState = plotPoints.OrderBy(p => p.StateName);

                var uniqueStates = orderedByState.Select(p => p.StateName).Distinct();

                var plotCount = 0;
                foreach (var state in uniqueStates)
                {
                    axisX.CustomTicks.Add(new CustomAxisTick {AxisValue = plotCount++, LabelText = state});
                }

                var distinctEconomies = new List<StateResourceType>();

                foreach (var stateData in orderedByState)
                {
                    foreach (var resourceData in stateData.Resources)
                    {
                        if (!distinctEconomies.Contains(resourceData.ResourceType))
                        {
                            distinctEconomies.Add(resourceData.ResourceType);
                        }
                    }
                }

                var barSeries = distinctEconomies.ToDictionary(
                    economy1 => economy1,
                    economy1 => ItemFactory.CreateBarSeries(chartView, axisX, axisY,
                        (b) =>
                        {
                            b.Title.Text = economy1.ToString();
                            b.BorderColor = Colors.DarkGray;
                            b.BorderWidth = 3;
                            b.IncludeInAutoFit = true;

                            switch (economy1)
                            {
                                case StateResourceType.Banking:
                                    b.Fill = new Fill() {Color = Colors.Green};
                                    break;
                                case StateResourceType.Logging:
                                    b.Fill = new Fill() {Color = Colors.Tomato};
                                    break;
                                case StateResourceType.Mining:
                                    b.Fill = new Fill() {Color = Colors.Orange};
                                    break;
                                case StateResourceType.Oil:
                                    b.Fill = new Fill() {Color = Colors.Violet};
                                    break;
                                case StateResourceType.Tech:
                                    b.Fill = new Fill() {Color = Colors.SpringGreen};
                                    break;
                                case StateResourceType.Tourism:
                                    b.Fill = new Fill() {Color = Colors.SkyBlue};
                                    break;
                            }
                        }));

                // Order the custom ticks by axis value... so we have the 0 items first, 1 items next, etc.
                var tickList = axisX.CustomTicks.Join(orderedByState, x => x.LabelText, s => s.StateName,
                    (c, s) => new TickStateInfo(c.AxisValue, s.StateName, s.Resources));
                var ticksOrderedByAxisValue = tickList.OrderBy(a => a.XAxisValue);

                foreach (var ticks in ticksOrderedByAxisValue)
                {
                    PlotPointItem(ticks, barSeries, axisX);
                }

                //AddseriestothePointLineSeriescontainerintheview
                barSeries.ForEach(l => chartView.BarSeries.Add(l.Value));

                barSeries.ForEach(l => l.Value.InvalidateData());

                DetermineGraphRanges();
                SpaceBars();
                PositionBarsCorrectly();
            }
        }

        private void DetermineGraphRanges()
        {
            // Find the bar spacing (in our case, bar spacing will be the spacing between groups of bars, not individual bars)
            var barSpacing = Chart.ViewXY.BarViewOptions.BarSpacing;

            // Find the minimum custom tick location
            var minimumCustomTickLocation = Chart.ViewXY.XAxes[0].CustomTicks.Min(ct => ct.AxisValue);

            // Find the maximum custom tick location
            var maximumCustomTickLocation = Chart.ViewXY.XAxes[0].CustomTicks.Max(ct => ct.AxisValue);

            // The min/max region we can draw in will take into account the bar spacing, so we give enough room on the left and right
            // of the chart
            var minScreenCoord =
                Chart.ViewXY.XAxes[0].ValueToCoord(minimumCustomTickLocation) - barSpacing;
            var maxScreenCoord =
                Chart.ViewXY.XAxes[0].ValueToCoord(maximumCustomTickLocation) + barSpacing;

            // We need to convert these values back to value points
            double minValueCoord;
            double maxValueCoord;

            if (Chart.ViewXY.XAxes[0].CoordToValue((int)minScreenCoord, out minValueCoord, false))
            {
                Chart.ViewXY.XAxes[0].Minimum = minValueCoord;
            }

            if (Chart.ViewXY.XAxes[0].CoordToValue((int)maxScreenCoord, out maxValueCoord, false))
            {
                Chart.ViewXY.XAxes[0].Maximum = maxValueCoord;
            }
        }

        private void SpaceBars()
        {
            // The min/max region we can draw in will take into account the bar spacing, so we give enough room on the left and right
            // of the chart
            var minScreenCoord =
                Chart.ViewXY.XAxes[0].ValueToCoord(Chart.ViewXY.XAxes[0].Minimum);
            var maxScreenCoord =
                Chart.ViewXY.XAxes[0].ValueToCoord(Chart.ViewXY.XAxes[0].Maximum);

            // Actual region we can draw in is this... the difference between the min and max screen coordinate
            // This would be for one bar, for instance
            var barWidth = (maxScreenCoord - minScreenCoord);

            // Find number of ticks graphed...
            var numberOfTicksGraphed = Chart.ViewXY.XAxes[0].CustomTicks.Count;

            // Find the bar spacing (in our case, bar spacing will be the spacing between groups of bars, not individual bars)
            var barSpacing = Chart.ViewXY.BarViewOptions.BarSpacing;

            // Take out the region we have for graphing based on the bar spacing and the number of items graphed...
            // We will use the spacing only between tick marks and groups of bars
            // Arction doesn't provide a way to space bars by grouping... we have to do this manually
            barWidth -= (barSpacing * (numberOfTicksGraphed - 1));

            // Count the total number of bars
            var barCount = Chart.ViewXY.BarSeries.Aggregate(0.0f, (current, barSeries) => current + barSeries.Values.Count());

            // Find what the bar width should be
            barWidth /= barCount;

            // Set all the bar widths
            foreach (var barSeries in Chart.ViewXY.BarSeries)
            {
                barSeries.BarThickness = (int)barWidth;
            }
        }

        private void PositionBarsCorrectly()
        {
            var barSpacing = Chart.ViewXY.BarViewOptions.BarSpacing;

            // Find current screen coordinate...
            var currentScreenCoordinate = Chart.ViewXY.XAxes[0].ValueToCoord(Chart.ViewXY.XAxes[0].Minimum) + barSpacing;

            // All bars are same thickness... just look at the first one
            var barThickness = Chart.ViewXY.BarSeries[0].BarThickness;

            // Figure out how many bars associated with the current x item... we can order the bar series by location
            foreach (var customTick in Chart.ViewXY.XAxes[0].CustomTicks)
            //for(int stateIndex = 0; stateIndex < currentStateCount; ++stateIndex)
            {
                //var currentGrouping = Chart.ViewXY.BarSeries.Where(barSeries => Math.Abs(barSeries.Values[0].Location - customTick.AxisValue) < float.Epsilon).ToList();

                var currentGrouping = new List<BarSeriesValue>();

                // Count number of items in this grouping...
                var count = currentGrouping.Count();

                // Total width of this region....
                float totalWidth = count * barThickness;

                // Find the middle of this region (the tick needs to go in the middle of the bar group)
                var correctBarLocation = currentScreenCoordinate + (totalWidth / 2);

                // Find end of this region in screen coordinates...
                currentScreenCoordinate += totalWidth;

                // Now, convert to value coordinate, and all items in this grouping will get updated to that position...
                var valueCoordinate = 0.0;

                if (Chart.ViewXY.XAxes[0].CoordToValue((int)correctBarLocation, out valueCoordinate, true))
                {
                    foreach (var barSeries in Chart.ViewXY.BarSeries)
                    {
                        for (var index = 0; index < barSeries.Values.Length; ++index)
                        {
                            if (Math.Abs(barSeries.Values[index].Location - customTick.AxisValue) < float.Epsilon)
                                barSeries.Values[index].Location = valueCoordinate;
                        }
                    }

                    // Need to update the custom tick location first...
                    customTick.AxisValue = valueCoordinate;
                }

                // Move to the next beginning of the bar (which should be based on the bar spacing...
                currentScreenCoordinate += barSpacing;
            }
        }

        protected override void Cleanup()
        {

        }

        private void PlotPointItem(TickStateInfo tick,
            Dictionary<StateResourceType, BarSeries> barSeries,
            AxisX xAxis)
        {
            var listUsed = new List<StateResourceType>();
            foreach (var resourceItem in tick.ResourceList)
            {
                BarSeries barItem;
                if (barSeries.TryGetValue(resourceItem.ResourceType, out barItem))
                {
                    barItem.AddValue(tick.XAxisValue, resourceItem.IncomeFrom, resourceItem.IncomeFrom.ToString(), true);
                    listUsed.Add(resourceItem.ResourceType);
                }
            }
        }


cwodarczyk82
Posts: 43
Joined: Mon Oct 19, 2015 2:50 am

Re: Trying to find workaround to some bar series issues

Post by cwodarczyk82 » Thu Nov 19, 2015 6:14 am

An update... I played with this a little more and realized I wasn't setting the values correctly to advance the x coordinates... here is how I have it fixed now for that method:

Code: Select all

        private void PositionBarsCorrectly()
        {
            var barSpacing = Chart.ViewXY.BarViewOptions.BarSpacing;

            // Find current screen coordinate...
            var currentScreenCoordinate = Chart.ViewXY.XAxes[0].ValueToCoord(Chart.ViewXY.XAxes[0].Minimum) + barSpacing;

            // All bars are same thickness... just look at the first one
            var barThickness = Chart.ViewXY.BarSeries[0].BarThickness;

            // Figure out how many bars associated with the current x item... we can order the bar series by location
            foreach (var customTick in Chart.ViewXY.XAxes[0].CustomTicks)
            {
                // Count number of items in this grouping...
                var count = Chart.ViewXY.BarSeries.Sum(barSeries => barSeries.Values.Count(values => Math.Abs(values.Location - customTick.AxisValue) < float.Epsilon));

                // Total width of this region....
                float totalWidth = count * barThickness;

                // Find the middle of this region (the tick needs to go in the middle of the bar group)
                var correctBarLocation = currentScreenCoordinate + (totalWidth / 2);

                // Find end of this region in screen coordinates...
                currentScreenCoordinate += totalWidth;

                // Now, convert to value coordinate, and all items in this grouping will get updated to that position...
                var valueCoordinate = 0.0;

                if (Chart.ViewXY.XAxes[0].CoordToValue((int)correctBarLocation, out valueCoordinate, true))
                {
                    foreach (var barSeries in Chart.ViewXY.BarSeries)
                    {
                        for (var index = 0; index < barSeries.Values.Length; ++index)
                        {
                            if (Math.Abs(barSeries.Values[index].Location - customTick.AxisValue) < float.Epsilon)
                                barSeries.Values[index].Location = valueCoordinate;
                        }
                    }

                    // Need to update the custom tick location first...
                    customTick.AxisValue = valueCoordinate;
                }

                // Move to the next beginning of the bar (which should be based on the bar spacing...
                currentScreenCoordinate += barSpacing;
            }

            Chart.ViewXY.XAxes[0].InvalidateCustomTicks();
        }

Which at first is giving me this result:

I also added a control to show me what the values are on the x and y axes (so I could see what the values were getting set to ):

[img]
6.5.5_AutoScaling.PNG
6.5.5_AutoScaling.PNG (223.51 KiB) Viewed 10233 times
[/img]

So, finally the tick marks are getting placed correctly! YAY... :oops:

But for some reason the alignments are still not correct right away... you can see what the values are in the text boxes and for some reason the scale values are changing from 0 on the left to 0.78... I am not actually doing that in my code... when I modify the scale in the control I added, things look better (I have to do the same for the right end too...)

[img]
6.5.5_ManualScaling.PNG
6.5.5_ManualScaling.PNG (232.48 KiB) Viewed 10233 times
[/img]

I must still be missing something... but I am not sure what exactly... the call to FitToView seems to squish things in:

[img]
6.5.5_FitToView.PNG
6.5.5_FitToView.PNG (232.05 KiB) Viewed 10233 times
[/img]

You can see what values got automatically set in the text boxes when I call that... anyway, I am getting closer and will keep you updated if I finally figure this out.... but if you know what's going on, also appreciated! :)

cwodarczyk82
Posts: 43
Joined: Mon Oct 19, 2015 2:50 am

Re: Trying to find workaround to some bar series issues

Post by cwodarczyk82 » Fri Nov 20, 2015 7:57 pm

So I think I mostly figured everything i needed out... I just changed the minimum range to 0.0 and everything seems adjusted now... I'm not quire sure how all the ranges should necessarily bet set, but everything looks pretty good.. I just have to figure out how to space the groups a little better, and most of my work will be done... once I am done I can post my code on here for anyone else interested in how to do all of this....

Pasi... thank you very much for all the hard work on your end... I apologize for not knowing whether my group was going to upgrade or not, I didn't mean to cause any annoyances on your end... :freak:

Thanks again!
--Chris

Post Reply