Colouring an Excel stacked bar chart's points in relation to a value assigned in a table - excel

I am trying to create a roadmap/timeline in Excel 2010 using a stacked bar chart. I have provided a link below to an image which should explain my intentions with the chart. I wish to present different events in the chart and they should be drawn in relation to their duration. The longer the event is, the longer its respective bar is.
I have managed to build a macro that creates a chart of my liking. However, I wish to add another functionality to it. As it can be seen from the picture below, there is a column called 'Type' in the original table. It stands for the status of the event, whether it is completed, canceled or being planned. My aim is to have the chart represent this data by coloring the bars either red (if canceled), green(if completed) or blue (if planned) depending on what value the particular event in question has in its Type row.
Below is the code behind the macro that the button 'Create a New Event View' uses. I would like to know how to implement the coloring, preferably in this very same macro so that the user only needs to click the button.
Sub CreateEventTable()
Dim timespan_start As Date
Dim timespan_end As Date
timespan_start = Application.InputBox("Type start date:")
timespan_end = Application.InputBox("Type end date:")
ActiveSheet.Shapes.AddChart(xlBarStacked, Range("E2").Left, Range("E2").Top).Select
With ActiveChart
.SetSourceData Source:=Range("$A$1:$B$12, $D$1:$D$12"), PlotBy:=xlColumns
.SeriesCollection(1).Values = Range("B2:B12")
.SeriesCollection(1).XValues = Range("A2:A12")
.SetElement msoElementLegendNone
.ChartGroups(1).GapWidth = 31
.SeriesCollection(2).ApplyDataLabels
.SeriesCollection(2).DataLabels.ShowCategoryName = True
.SeriesCollection(2).DataLabels.ShowValue = False
.SeriesCollection(1).Format.Fill.Visible = msoFalse
.Axes(xlValue).MinimumScale = timespan_start
.Axes(xlValue).MaximumScale = timespan_end
End With
End Sub
Here is the link to the image which hopefully explains the overall structure:
http://i.imgur.com/XzPoMiY.jpg
I appreciate your invaluable help! I am happy to provide more details if deemed necessary.

Best solution here is not VBA. You'll need to create multiple series for your chart, have them overlapped, and use formulas to populate if they meet the criteria. Changes automatically, and very easy to maintain.
As Skip Intro said, Jon Peltier is the chart master.
This link will get you started in the right direction.
http://peltiertech.com/WordPress/conditional-formatting-of-excel-charts/

Related

When I add a chart into excel using VBA sometimes it becomes a pivot chart and causes errors

I have a pivot table with 3 values in it. Volume Processed, Volume Billed, and Billed Revenue. VB is always a subset of VP, and BR is often in the 100,000s compared to VB and VP which are usually less than 1,000. Additionally, there are over 1000 data points in my test data. I've only loaded in 2 months, and when it's done it has to be able to quickly handle an entire year. So Pivot Charts won't work. BR is a currency and VB and VP are just numbers. The chart I want is to show (VP-VB) stacked on top of VB where the height of VB = BR and the height of (VP-VB)+VB = (VP*BR)/VB. I also try to use a smaller amount of data points. If all the IDs are showing, that's over 1000 columns on the graph, it's much easier to see them group by buildings until you use a slicer to bring down the number of IDs to something more manageable.
My solution is to use VBA to make my own graph, scrape the data from the pivot table, figure out what graph the user wants to see, and then build it from scratch.
The problem is that sometimes the chart preloads with a pivot chart and then when I try to add in my data it throws a Run-time error. I am having trouble even creating the error because it doesn't always happen.
Dim MyChart as Object
Dim chtrng as Range
Dim srs as Series
Dim arrayvalues() as Double
Dim areayXvalues() as Variant
Set chtrng = Sheets("Pivot").Range("H30:T50")
Set MyChart = ThisWorkbook.Sheets("Pivot").ChartObjects.Add(Left:=chtrng.left,Width:=chtrng.width,Top:=chtrng.Top,Height:=chrrng.Height)
With MyChart.Chart
.ChartType = xlColumnStacked
.Has title = True
.ChartTitle.text = GraphName(0)
For j = 1 to 2
For I = 1 to GraphList.Count
Arrayvalues(i-1) = GraphList(I)(j)
Next I
Set srs = .Series collection.NewSeries
With srs
.Xvalues = areayXvalues
.Values = areayvalues
.Name = GraphName(j)
End With
Next j
End With
"Set srs" is where the error comes in. This is also the first pass of j. When I step through the code, the times that it works, at "Set MyChart" the graph is empty, but the times it doesn't work, the graph has a pivot chart inside. At the beginning of the actual code I delete all charts on the sheet.
Every scenario I try, with different data displayed in the pivot table has done both. I can't figure out what is even causing the issue.
I've tried making sure MyChart is set to nothing. I have code that calls the makegraph sub when the pivot table updates, I created a on/off switch for that. I've tried to disconnect all of my data scraping from the pivot table so that by the time I start on the graph none of my variables are attached to the table.
Most of the time the graph works exactly as expected, but every now and then it gives me a Run-time error '1004' on "Set srs"

Excel keyboard ability to change a value in a displayed dynamic chart range line

I plan to have a chart plotted line consisting of 20 values set up as a dynamic chart range. I then can manually go into the sheet and update these values one at a time and the chart will change its display.
But instead of manually changing the sheet values, I want to be able to;
1. Move the cursor to one of the displayed points on the line [using mouse?].
2. Use the up/down arrow keys to change the value of the point [to the value of the y axis where the point is moved to]. The incremental value the point is moved up/down with the arrow keys can be a tunable value in the sheet.
3. As the point value changes, the line should re-plot using the latest updated 20 values in the range.
Thank you.
Don
Tried nothing yet. Just an idea I want to use in possible applications.
No code for this change.
The problem summary details the results.
P.S. Since I got a -1 vote, I thought I should add more about what this would be used for in real life.
I have Macular Degeneration, but slowed it down from getting worse many years ago, and get regular shots in the one bad eye. Over the years, the original Amsler Grid has been manually used by patients to check for a deterioration in the condition, so they can quickly see their Eye Doc to get a shot before it gets worse. Lately, machines have been built that can test for the condition worsening, and report it to the user and/or their doctor. However, these machines are expensive. And the Amsler grid results are very subjective.
My idea is to develop an Excel sheet with chart to replace the Amsler Grid with one straight line that can be shown at any angle through a center point and allow anyone with Excel to test their eyes with this dynamic replacement. The Amsler grid has a Dot in the center and a bunch of horizontal and vertical grid lines. You cover one eye and with the other, look at the centered dot and then subjectively determine if you see the grid lines perfectly, of if they appear distorted.
What I want to do is to have a chart on which the user can selectively spot any distorted portions of the line, click on a distorted spot on the line, then "move" the spot to line up with the users view of the rest of the line. After the user has "straightened" out the line, he submits it. The logic then inverts the corrected line [which in reality is inversely distorted by the users movements of points on the line] and then this line is sent to the doctor involved via email. The doc can then determine how bad the distortion is by comparing it to past emailed lines from the same user and comparisons to the perfect straight line the user started with, and an appointment can be made for an office visit.
I can handle the best fit quadratic logic for displaying the line through the points, starting with linear, then fitting to what the users distorted results are. I just need help on the originally stated questions.
So here is my take on this (maybe there are more elegant ways), it's oversimplyfied to what you want I guess and not all your questions get answered, but maybe you'll get to implement some of it.
1) Create a chart on it's own seperate sheet, my example data on a line graph:
2) Assign code to Private Sub Chart_Activate and Private Sub Chart_Deactivate, for example:
Private Sub Chart_Activate()
Application.OnKey "{UP}", "GoUp"
Application.OnKey "{DOWN}", "GoDown"
End Sub
Private Sub Chart_Deactivate()
Application.OnKey "{UP}", ""
Application.OnKey "{DOWN}", ""
End Sub
3) The OnKey will activate two modules called GoUp or GoDown, I have written them as follows (maybe it can be done better)
Sub GoUp()
If TypeName(Selection) = "Point" Then
For Each pt In ActiveChart.SeriesCollection(1).Points
x = x + 1
If pt.Name = Selection.Name Then
With ThisWorkbook.Sheets("Sheet1")
.Range("A" & x).Value = .Range("A" & x).Value + 1
End With
Exit For
End If
Next pt
End If
End Sub
Sub GoDown()
If TypeName(Selection) = "Point" Then
For Each pt In ActiveChart.SeriesCollection(1).Points
x = x + 1
If pt.Name = Selection.Name Then
With ThisWorkbook.Sheets("Sheet1")
.Cells(x, 1) = .Cells(x, 1) - 1
End With
Exit For
End If
Next pt
End If
End Sub
Change the +1 and -1 to an assigned variable if need be.
4) Result on pressing arrow down or up when a point is selected:

From a selected line in a chart, filter a table or pivot table

I am facing a challenge. In a chart with multiple lines, I would like to able when I click on a line or mouse over a line to see the corresponding datapoint in the the table or pivot table...So basically, filtering a table based on the element i click or select on a chart with my mouse.
Do you think that it is achievable ? What would be the methodology ? Is there a VBA code for this ? I have seen examples, but they are working on the oppiste way; click or mouse over an observation and the line is highlighted...
Thanks in advance
saskap
This is really complicated, you have to customize the code for each chart, this example code can be a starting point:
Dim p As Series
Dim pc As Long
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim ch As ChartObject: Set ch = Me.ChartObjects("Chart 1")
With ch
Dim s As Series: Set s = Nothing
On Error Resume Next: Set s = .Chart.SeriesCollection(Target.Value): On Error GoTo 0
If Not p Is Nothing And Not p Is s Then
p.Format.Fill.ForeColor.RGB = pc
End If
If Not s Is Nothing Then
Set p = s
pc = s.Format.Fill.ForeColor.RGB
With s
s.Format.Fill.ForeColor.RGB = RGB(255, 0, 0)
End With
End If
End With
End Sub
The first two rows are global variables that store which Series
object was highlighted last time and what was its original color,
this is needed to restore the original color when a different cell is
selected. Unfortunately global variables in VBA loose their value when the project is reset (e.g. the Stop button is pressed or an error occurs), so it is possible that this code colors a bar and then cannot color it back. If important, these information may be stored in invisible Cells or Chart data but that complicates the code.
The next line means that this is an event handler, a function that is called in response to a certain event, in this case when the selection changes on a certain worksheet (the one on which you insert this - you have to insert this into a worksheet module not a standard code module).
Next we look up the chart based on its name and assign it to a variable, which is of type ChartObject, so early binding will allows us to depend on the support of intellisense (if you type a . it shows members of interfaces).
Then we look up the Series inside the chart based on the name found in the newly selected cell's contents. Since we don't know if the new cell will have a valid name, we have to protect this line with disabling error handling and checking later if the s has a non-nothing value. - This part depends largly on the type of chart and how it represents data, it is possible that you will have to select data based on Series::XValues.
We check if there is a saved value for a previously highlighted bar and if it is different from the current selection, restore its original color.
Finally if the looking up the Series earlier was successful then s is non-null and we save the color of the current bar and highlight it with red fill.

Scatter plot references row numbers rather than selected data

EDIT: The problem is that the scatter graph is plotting my data against the row number, rather than the selected x-axis. When i change to a line graph, it does it correctly, but my VBA only works on scatter plots so i need to either make this graph reference the correct data or alter my code to make it work on line charts. I checked that the data is formatted as numbers, not text, but still no improvements.
I created a spreadsheet for work in which my coworkers drag and drop data into a sheet. A report is generated on another sheet which includes a graph of the raw data.
I used "define names" for each column of data so that the correct range would be selected no matter how large the dataset is. This worked beautifully, graph would update itself every time data was changed. Then I ran VBA to scale the axes and it all got messed up
When I run the code below, The axes get scaled just like I intended them to, but now, instead of having nice cycles in the data, the graph just shows a straight horizontal line for each set of data. I checked "select data" and everything is still selected correctly, and the data is the same as it was before I hit "run," only the graph doesn't look right. Here is the code:
Private Sub Worksheet_Calculate()
ScaleAxes
End Sub
Sub ScaleAxes()
'With Application.ActiveChart.Axes(xlCategory, xlPrimary)
With ChartObjects(1).Chart.Axes(xlCategory, xlPrimary)
.MinimumScale = ActiveSheet.Range("B26").Value
.MaximumScale = ActiveSheet.Range("B25").Value
.MajorUnit = 5
End With
'With Application.ActiveChart.Axes(xlValue, xlPrimary)
With ChartObjects(1).Chart.Axes(xlValue, xlPrimary)
.MinimumScale = ActiveSheet.Range("C26").Value
.MaximumScale = ActiveSheet.Range("C25").Value
.MajorUnit = 10
End With
End Sub
I really can't see what the problem is. The data is correct, it displayed on the graph correctly before code was run. Code works fine for scaling axes, but for some reason ruins the data inside the graph.

How to plot chart values outside axis maximum?

In previous versions of Excel there was a registry entry that you could create to allow Excel to display values/labels that would be positioned outside the axis min/max using QFE_Bonn dword=1. This is what I have used for Excel 2003: Plot lines that contain labels disappear ...)
I have not been able to find a similar patch or native functionality in Excel 2010 (Office Pro Plus). Any ideas how this can be accomplished, or did MS remove this functionality altogether?
Here are screenshots of examples in Excel 2003. I create a series of data which uniformly exceeds the y-axis maximum. This series' color fill has been removed already
To finish the look, remove the series' border so that it appears invisible. Then replace the series' value labels with the relevant data.
There is a workaround using the DataLabels.Left property which positions the DataLabel relative to the ChartArea.
Here is an example VB solution:
sub FakeLabels()
Dim sF As Double
Dim lOff As Double
Dim p As Double
ActiveSheet.ChartObjects(1).Activate
With ActiveChart
For sF = 1 To .SeriesCollection.Count
If .SeriesCollection(sF).Name = "FakeSeries" Then
'Define the lOff variable by adding 100, or some other value
lOff = .SeriesCollection(sF).Points(1).DataLabel.Left + 100
For p = 1 To .SeriesCollection(sF).Points.Count
.SeriesCollection(sF).Points(p).DataLabel.Left = lOff
Next p
End If
Next sF
End With
It yields the same results, the only new requirement is to keep the values for the "dummy" series within the axis min/max values for the chart.
A pleasant surprise is that re-sizing the chart doesn’t appear to affect the relative placement of the labels.
UPDATED 9-25-2013
I have used the "textbox" approach since first asking this question. But it is extremely clunky to manage the interplay between the labels' position and the textbox positions, their relative position of the PlotArea i.e., when to use .InsideWidth vs. .Width or .InsideLeft vs. .Left and whether there needs to be any sort of hedonic "adjustments" to the points values, as always seem to be the case, they are never quite perfectly aligned.
While perusing the PPT object model reference for some other chart-related inquiries, I stumbled upon this property which appears to replicate the functionality of the previous hotfix/registry hack.
.ShowDataLabelsOverMaximum

Resources