I work heavily with PivotCharts, but have absolutely zero VBA experience. I have excel templates that are uploaded to a database, then can be downloaded as a report with the data from that database. I have a pivotTable/PivotChart combo on one sheet. Sometimes the table has 5 rows of data, and sometimes is has 1200 rows of data, depending on the database, timeframe, etc.
What I'd like to do, is have the chart take up the same number of rows as the table + 3 in height, and always display in D3:J3 for width and starting position. This aligns the data with the charts.
I have found a similar ? from last year here: Resize pivot chart when selecting different less/more values
It has not gotten me any results (or I'm doing something wrong).
Relevant info: table/chart is on Sheet4 ("Summary"), and under PivotTable Options, it is called "IdleSummary".
I appreciate any help that can be given, thanks!
One way to do it, is to use a range object to size your chart like so:
Sub test()
Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets("Summary")
Dim vPiv As PivotTable
Dim vRowCount As Long
Dim graphSizer As Range
Dim theChart As ChartObject
Set vPiv = ws.PivotTables("IdleSummary")
vRowCount = ws.Range(vPiv.TableRange2.Address).Rows.Count + 3
Set graphSizer = ws.Range("D3:J" & vRowCount)
Set theChart = ws.ChartObjects.Add(Left:=graphSizer.Left, Top:=graphSizer.Top, Width:=graphSizer.Width, Height:=graphSizer.Height)
With theChart.Chart
.SetSourceData vPiv.TableRange2
.ChartType = xlArea 'replace with desired chartType
End With
End Sub
EDIT, to answer comments:
Modifying the above code, and using the worksheet PivotTableUpdate event you could do like so:
Private Sub Worksheet_PivotTableUpdate(ByVal Target As PivotTable)
If Target.Name = "IdleSummary" Then
Call Resize
End If
End Sub
Sub Resize()
Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets("Summary")
Dim vPiv As PivotTable
Dim vRowCount As Long
Dim graphSizer As Range
Dim theChart As ChartObject
Dim charObj As ChartObject
Set vPiv = ws.PivotTables("IdleSummary")
vRowCount = ws.Range(vPiv.TableRange2.Address).Rows.Count + 3
Set graphSizer = ws.Range("D3:J" & vRowCount)
Set theChart = ws.ChartObjects(1)
With theChart.Chart.Parent
.Left = graphSizer.Left
.Top = graphSizer.Top
.Width = graphSizer.Width
.Height = graphSizer.Height
End With
End Sub
This is assuming you have just one chart, else you can replace the index (1) with the chart name, e.g. ("Chart 1"). If you interested in reading about events you can find an introduction here: http://www.cpearson.com/excel/Events.aspx
Related
I created an Excel 2016 VBA scatter chart (separate worksheet w/o legends) and labeled the points with VBA. Source labels are A1:A3 (Events (35-chars) / Date / Y-points) and Data is A2:C17. My labels (orientation -90) overwrite the Y-points and bunch up because the Y-axis plot area takes up the entire worksheet. I have tried different Y-axis values but the plot area expands to fill the worksheet. I have also tried to change the plot size with VBA. I need the labels above the actual chart plot.
The secondary issue is I cannot plot a Date & Time, just a Date and have a problem creating Error Bars with xlMinusValues 100% and SeriesCollection(1).
I have been doing this in separate modules for ease of use, but will be combining or using a Call. I find I cannot build a chart with more than 16 data records, so I will be working on a looping routine if more records are present.
TIMELINE MODULE
Option Explicit
Sub Timeline()
Dim sCount As Long
Dim labelrotation As Long
Dim TimelineChart As Chart
Dim LastCell As Long
Dim rng As Range
Dim rngAddr As String
Dim ChartRange As String
With ActiveSheet
Range("C1").End(xlDown).Activate
Set rng = ActiveCell
rngAddr = rng.Address(0, 0)
End With
Let ChartRange = "B2:" & rngAddr
Set TimelineChart = Charts.Add
TimelineChart.Name = "TimelineChart"
With TimelineChart
.SetSourceData Sheets("TimelineData").Range(ChartRange)
.ChartType = xlXYScatter
.Legend.LegendEntries(1).Delete
TimelineChart.HasAxis(xlSecondary) = False
End With
End Sub
LABEL MODULE
Option Explicit
Sub Labels()
Dim r As Range
Dim Events As Range
Dim EventCounter As Integer
Dim s As Series
Sheets("TimelineData").Select
Set Events = Range("A2", Range("A1").End(xlDown))
Set s = Chart1.SeriesCollection(1)
s.HasDataLabels = True
For Each r In Events
EventCounter = EventCounter + 1
s.Points(EventCounter).DataLabel.Text = r.Value
s.Points(EventCounter).DataLabel.Position = xlLabelPositionAbove
s.Points(EventCounter).DataLabel.Orientation = 45
Next r
End Sub
I am going to withdraw the question. The scatter plot was on a chart sheet versus in the same worksheet as the table from which data is used. Lots of hours spent with a conclusion I should use a bar chart, same worksheet, modified.
Thanks to all that looked and considered a response.
I'm a novice VBA user and already posted on this issue, but had to re-do some tables in my workbook and the initial question ended up being inaccurate, hence trying again.
I have modified a code found online to work with my workbook which:
links a cell to a my pivot table filter;
updates the filter and refreshes pivot table once the cell has been updated or activated;
Works great. The challange is that there are 2 pivot tables on the same worksheet and I'd need to filter 2 tables at the same time. Also the filter data is different, so the filter should be linked to different cells, although they do change at the same time.
The code I was using is below. Now there is PivotTable1 and PivotTable2; entry to cell H6 is linked to the 1st table and H7 to the other table. Got a little overwhelmed at this point, but this should be possible within the same code, right?
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
'This line stops the worksheet updating on every change, it only updates when cell
'H6 or H7 is touched
If Intersect(Target, Range("H6:H7")) Is Nothing Then Exit Sub
'Set the Variables to be used
Dim pt As PivotTable
Dim Field As PivotField
Dim NewCat As String
'Here you amend to suit your data
Set pt = Worksheets("Sheet1").PivotTables("PivotTable1")
Set Field = pt.PivotFields("Category")
NewCat = Worksheets("Sheet1").Range("H6").Value
'This updates and refreshes the PIVOT table
With pt
Field.ClearAllFilters
Field.CurrentPage = NewCat
pt.RefreshTable
End With
End Sub
Your code can be amended as follows...
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
'This line stops the worksheet updating on every change, it only updates when cell
'H6 or H7 is touched
If Intersect(Target, Range("H6:H7")) Is Nothing Then Exit Sub
'Set the Variables to be used
Dim pt As PivotTable
Dim Field As PivotField
Dim vPivotTableNames As Variant
Dim vNewCats As Variant
Dim i As Long
'Assign the pivottable names to a variable
vPivotTableNames = Array("PivotTable1", "PivotTable2")
'Assign the new categories to a variable
vNewCats = Range("H6:H7").Value
'Update the pivotables
For i = LBound(vPivotTableNames) To UBound(vPivotTableNames)
Set pt = Worksheets("Sheet1").PivotTables(vPivotTableNames(i))
Set Field = pt.PivotFields("Category")
With Field
.ClearAllFilters
.CurrentPage = vNewCats(i + 1, 1)
End With
pt.RefreshTable
Next i
End Sub
Although, the For/Next loop can be re-written as follows...
'Update the pivotables
For i = LBound(vPivotTableNames) To UBound(vPivotTableNames)
With Worksheets("Sheet1").PivotTables(vPivotTableNames(i))
With .PivotFields("Category")
.ClearAllFilters
.CurrentPage = vNewCats(i + 1, 1)
End With
.RefreshTable
End With
Next i
Private Sub CommandButton1_Click()
Dim tl As Integer
t1 = 33
'**************
Dim tbl1 As Table
Dim rng As Range
Set doc = ActiveDocument
Set tbl1 = ActiveDocument.Tables(t1)
Set rng = doc.Range(Start:=tbl1.Cell(2, 5).Range.Start, _
End:=tbl1.Cell(100, 5).Range.End)
rng.Text = TextBox1.Text
When I press the button, this code does not work properly, I can fill only Start:=tbl1.Cell(2, 5).... This fills only 1 cell
But End:=tbl1.Cell(100, 5).Range.End) doesn't work. It does not fill all the rows.
You need to loop through all of the cells concerned. For example:
Private Sub CommandButton1_Click()
Dim tl As Long, r As Long
t1 = 33
With ActiveDocument.Tables(t1)
For r = 2 To 100
.Cell(r, 5).Range.Text = TextBox1.Text
Next
End With
End Sub
If you want to use the same technique that you discovered for copy one cell to multiple cells, that should also work. It's a bit tricky, though, and you don't give us enough information to reproduce the TextBox, so you may need to tweak the following.
I put the ActiveX text box on the document surface and pick it up using the InlineShapes collection. If you're using a UserForm you'll need to change that part.
It's not possible to assign a Column in Word to a Range object. A Range must be a contiguous flow of text. In Word, the contiguous flow is horizontal, then vertical - so Rows can be assigned to a Range, but not a column. (And that is why the other Answer loops the cells in the column, which is comparatively slow.)
It is possible, however, to select a column and work with the Selection. So the code below copies the content of the text box to the clipboard, then selects the entire column and pastes to the Selection.
Sub CopyToMultipleCells()
Dim tl As Integer
Dim doc As word.Document
Dim tb As MSForms.TextBox
tl = 1
'**************
Dim tbl1 As Table
Dim rng As Range
Set doc = ActiveDocument
'Change if on a UserForm
Set tb = doc.InlineShapes(1).OleFormat.Object
'Select the text box content, then copy it
tb.SelStart = 0
tb.SelLength = tb.TextLength
tb.Copy
Set tbl1 = ActiveDocument.Tables(tl)
tbl1.Columns(5).Select
Selection.Paste
End Sub
I need to create Bar chart in Excel VBA. I used the code below, but when I am ADDING or DELETING A ROW it is not working.
I need that chart on fixed range (K1). Because when I am calculating for the second time it creates another chart.
How can I change the code to prevent a new chart being added when I adjust the data source?
Private Sub CommandButton2_Click()
Sheets("Sheet7").Range("F2:H12").Select
ActiveSheet.Shapes.AddChart.Select
ActiveChart.ChartType = xlBarClustered
ActiveChart.SetSourceData Source:=Range("Sheet7!$F$2:$H$12")
ActiveChart.SeriesCollection(1).Name = "=Sheet7!$G$1"
ActiveChart.SeriesCollection(2).Name = "=Sheet7!$H$1"
End Sub
In the sample code below it checks to see if a chart called TheChart already exists, and if not, creates a new one. You can now add and remove rows and the chart should will update. Additionally, if you add a new row at the bottom and click the button it will redraw TheChart without creating a new one.
The chart is always located at the top-left of K1 per the rngChartTopLeft variable - which you can adjust if required.
The code assumes that it is running in a Sheet module (hence Set ws = Me) and if you were running it in a standard module you can set the sheet with Set ws = ThisWorkbook.Worksheets("your_sheet").
Option Explicit
Private Sub CommandButton1_Click()
Dim ws As Worksheet
Dim chto As ChartObject
Dim rngChartTopLeft As Range
Dim rngData As Range
' assumes the code is in a sheet object
Set ws = Me
' top left of chart
Set rngChartTopLeft = ws.Range("K1")
' create chart or get existing chart
If ws.ChartObjects.Count = 0 Then
Set chto = ws.ChartObjects.Add( _
Left:=rngChartTopLeft.Left, _
Width:=500, _
Top:=rngChartTopLeft.Top, _
Height:=500)
chto.Name = "TheChart"
Else
Set chto = ws.ChartObjects("TheChart")
End If
' set chart type
chto.Chart.ChartType = xlBarClustered
' get data range per last row of data
Set rngData = ws.Range("F2:G" & ws.Cells(ws.Rows.Count, "G").End(xlUp).Row)
' set new chart range
chto.Chart.SetSourceData rngData
End Sub
please check the below code:
Option Explicit
Private Sub CommandButton1_Click()
Dim mychart As Shape
Dim lastrow As Long
lastrow = Sheet7.Cells(Rows.Count, "F").End(xlUp).Row
For Each mychart In ActiveSheet.Shapes
If mychart.Name = "CommandButton1" Then GoTo exit_
mychart.Delete
exit_:
Next
Sheets("Sheet7").Range("F2:H" & lastrow).Select
ActiveSheet.Shapes.AddChart.Select
ActiveChart.ChartType = xlBarClustered
ActiveChart.SetSourceData Source:=Range("Sheet7!$F$2:$H$" & lastrow)
ActiveChart.SeriesCollection(1).Name = "=Sheet7!$G$1"
ActiveChart.SeriesCollection(2).Name = "=Sheet7!$H$1"
End Sub
I'm trying to generate two charts using VBA. The problem is most examples use ActiveChart but I want multiple charts on multiple sheets. If I inserted a blank chart how do I rename that chart to reference it. I don't want a new chart to be generated each time I run the macro and I want it to be in the sheet. I'm struggling with the code but am assuming it will be something like the code below. I've attached the desired graph (I made this through excel, but I need to do it through VBA).
macro1()
lastrow2 = Sheet1.Cells(Sheet1.Rows.Count, "A").End(xlUp).Row
dim chart1 as chart
dim chart2 as chart ' ect
chart1.title = "test"
chart1.xaxis = sheet1.cell(lastrow2,1)
chart1.yaxis = "manhours"
end sub
using a the record function, i got the code commented below. I tried to change it but i'm still having issues
Sub Macro7()
Dim Chart2 As ChartObject
Dim chartb As Chart
Chart2 = Sheet1.chartb.SeriesCollection(2)
chartb.Select
Formula = "=SERIES(Master!R3C3,Master!R4C1:R18C1,Master!R4C3:R19C3,2)"
' ActiveChart.SeriesCollection(2).Select
' Selection.Formula =_
'"=SERIES(Master!R3C3,Master!R4C1:R18C1,Master!R4C3:R19C3,2)"
End Sub
I really just need this formula converted to i can reference my lastrow function and individual sheets
ActiveChart.SeriesCollection(2).Select
Selection.Formula =_
"SERIES(sheet1.cells(3,3),sheet1.cells(4,1):sheet1.cells(18,1)_
,sheet1.cells(4,3):sheet1.cells(4,19),2"
' Selection.Formula"_
' =SERIES(Master!R3C3,Master!R4C1:R18C1,Master!R4C3:R19C3,2)"
this was what i was trying to do. It declares the sheet name and references an existing chart named chart 1.
Dim cht As ChartObject
Dim rng As Range
Set cht = Sheets("Master").ChartObjects("Chart 1")
Set rng = Sheets("Master").Range("A4", Range("D4").End(xlDown).Offset(-1))
cht.Chart.SetSourceData Source:=rng
cht.Chart.HasTitle = True
cht.Chart.ChartTitle.Text = "Bird Report - By Cost Code/Activity" ' title
cht.Chart.SeriesCollection(1).Name = "=Master!$B$3"
cht.Chart.SeriesCollection(2).Name = "=Master!$C$3"
cht.Chart.SeriesCollection(3).Name = "=Master!$D$3"