I am trying to resize an excel chart with VBA.
Is it possible to change ActiveChart.ChartArea.Height without affecting the size of the PlotArea? Whenever I attempt to change the chart height it looks like the plot area is automatically resized, which is an undesired outcome.
I have tried the following sequence, when downsizing a graph:
Changing plotarea to fixed desired height;
Changing chart height to fixed desired height;
Changing plotarea to fixed desired height;
This sequence does not yield expected results, as (1) the chart is not changed to specified height, and (2) the plotarea height is output correctly, but its positioning within the chart (.InsideTop) has changed.
Please, test the next way of dealing with a chart dimensions. The scenario involves the next process: firstly memorizing the PlotArea dimensions (Height/Width), then play with the chart (Object) dimensions, reset the PlotArea ones and set its Position to Automatic. Excel tries guessing what you want accomplishing and it looks/is more probable that both chart elements to be modified proportionally:
Sub testActiveChartDimensions()
Dim ch As Chart, plHeight As Double, plWidth As Double
Set ch = ActiveChart 'plays with a selectded chart
plHeight = ch.PlotArea.height: plWidth = ch.PlotArea.width 'memorize the plot area dimensions
ch.Parent.height = ch.Parent.height * 2: ch.Parent.width = ch.Parent.width * 2 'resize the chartObject
ch.PlotArea.height = plHeight: ch.PlotArea.width = plWidth 'reset the initial dimensions for plot area
' you can set any other dimensions (just to be lower than the new chart dimensions...)
ch.PlotArea.Position = xlChartElementPositionAutomatic 'center it on the chart object
End Sub
Related
I have an existing Excel file I need to work with. It contains a line graph where measurement results are plotted. All the referencing is done via names. The graph is called "ChartResult".
Obviously Excel discriminates the graph area (the "outer") and the plot area (the "inner") where the graph is plotted. Please correct me if I'm wrong, also learning the preferred english nomenclature would be of great help.
My goal is to print the (page containing the) table so that the division/auxiliary lines have a specific distance from each other. My thinking was that if I define the scale of the axis (the max and min values) and define a size of the graph I would acheive this goal.
However in Excel I can only type in the size of the whole graph area, which is the outer thing, so not helpful when I want to define the size of the graph, the inner thing.
I started using VBA to acheive this but haven't been succesful:
Sub Groesse_eingeben()
ActiveSheet.ChartObjects("ChartResult").Activate
ActiveChart.SeriesCollection(1).Select
ActiveChart.PlotArea.Select
Selection.Left = 0
Selection.Top = 0
Selection.Width = 200
Selection.Height = 200
End Sub
This code is changing the size an position of the graph but not to what I expected it to be. Is the input of Selection.XY in pixels or mm? I naively assumed mm but my graph becomes smaller than 200x200 mm, around 60x60 mm.
Thank you!
Chris
System:
Microsoft® Excel® 2016 MSO (Version 2204 Build 16.0.15128.20128)
Win10 Pro 21H2
Update:
Ok, the input size is points. But how to specify the exact size of the graph?
On the screenshot there are two dotted borders: One, the inner, is the actual size of the visible graph the other is the size of the graph object. To cause more confusion: Both are within the graph area, which I called "outer" area above :)
How can I input the exact numbers for the actual visible graph?
You can control the outer width of the chart (ChartObject) with the .Width property, and the inner width of the chart with the .Chart.PlotArea.Width property.
Here is a sub that takes a chart and widths as inputs, and updates the chart:
Private Sub SetChartWidths(Ch As ChartObject, OuterWidth As Long, InnerWidth As Long)
' Set the outer width of the chart
Ch.Width = OuterWidth
' Set the inner width (plot area width)
Ch.Chart.PlotArea.Width = InnerWidth
End Sub
EDIT START
And here is how you can use the sub:
Private Sub UseSubroutine()
' Store the chart object in a variable
Dim LineChart As ChartObject
Set LineChart = ThisWorkbook.Sheets("Sheet1").ChartObjects(1)
' Run the sub
SetChartWidths Ch:=LineChart, OuterWidth:=200, InnerWidth:=150
End Sub
If you're having trouble using the SetChartWidths sub, and it is in a different Module than the code you're calling it from, you can remove the Private from the front to change the Scope of the sub.
EDIT END
As for what widths to use, that will be up to you.
Hi I have developed VBA code that uses a user input to creates a bar chart. The number of bars in this chart can vary from the different users inputs. Unfortunatly I cannot think of a way to alter the size of the chart according to the number of bars.
I was wondering if anyone had any suggestion on how to do this.
Usually, when you want to make a change with VBA and you don't know where to start from you can try to record a macro while you perform the action manually and then check the generated code to see the output.
For example, if I select a chart inside a sheet and resize it, I get the following code:
ActiveSheet.Shapes("Chart 1").ScaleHeight 1.5, msoFalse, msoScaleFromTopLeft
ActiveSheet.Shapes("Chart 1").ScaleHeight 1.5, msoFalse, msoScaleFromTopLeft
You can then use this as a hint of how to write your code. For instance, you can make the scaling factor depend on the number of bars instead of being fixed at 1.5 in the example above.
Or, even better, instead of scaling the chart, you can specify the dimensions directly using the Height and Width properties:
ActiveSheet.Shapes("Chart 1").Height = 300
ActiveSheet.Shapes("Chart 1").Width = 100 + NumberOfBars * 15
Using the ChartArea object
The down side of the code above is that you need the name of the shape. If you want to edit the size of a chart that is currently selected without knowing its name, you could also use the following that makes use of the Height and Width properties:
Dim chrtArea As ChartArea
Set chrtArea = Selection
chrtArea.Height = 300
chrtArea.Width = 100 + NumberOfBars * 15
Or alternatively, you could assign the chrt variable as you create it which would make your code even more reliable.
How to get the number of bars?
Assuming you have only one series of data, you can get the number of observations which will be the number of bars:
Dim NumberOfBars As Long
NumberOfBars = UBound(chrtArea.Parent.SeriesCollection(1).XValues)
I have an Excel chart which changes on selections made in slicers.
I noticed that the plot area and the legend area change depending on the made selection.
I tried to fix the position and size for the plot area using vba, but this simply does not work unfortunately.
The plot area and the legend keep on resizing, causing the legend overlapping the plot area. Which I obviously do not want.
I have this code, placed in the worksheet page of the vba editor:
Option Explicit
Private Sub Chart_Calculate()
ChartObjects("grafiek 4").Activate
ActiveChart.PlotArea.Width = 637.783
ActiveChart.Legend.Left = 716.514
ActiveChart.Legend.Width = 176.735
ActiveChart.Legend.Height = 295.334
End Sub
having this code, I assumed the automatic resizing would be gone, but I saw the legend sometimes still overlaps te plot area.
Is there a solution which permanently fixes this problem?
Edit1:
Yesterday, I simply added a few parameters for the plot area. It seemed to work then. But now I tried again, and the legend is overlapping the plot area again.
I changed the code to:
Option Explicit
Private Sub Chart_Calculate()
ChartObjects("grafiek 4").Activate
ActiveChart.PlotArea.Top = 33.102
ActiveChart.PlotArea.Left = 67.1
ActiveChart.PlotArea.Width = 637.783
ActiveChart.Legend.Top = 7
ActiveChart.Legend.Left = 716.514
ActiveChart.Legend.Width = 176.735
ActiveChart.Legend.Height = 329.667
End Sub
So with 2 more paramters for the plot area.
edit2:
I have checked the legend properties in Excel. under 'options for legend' there is a checkbox: show legend without overlapping plot area (I do not know the exact english text).
This box is checked, but it does overlap the plot area.
Why is it impossible to achieve this? Having fixed sizes for the plot area and the legend should not be so hard.
edit 3:
I do have this routine now in my workbook:
Option Explicit
Private Sub Chart_Calculate()
ChartObjects("grafiek 4").Activate
With ActiveChart
With .PlotArea
.Top = 33.102
.Left = 67.1
.Width = 637.783
End With
With .Legend
.IncludeInLayout = True
.Position = xlLegendPositionRight
.AutoScaleFont = False
.Font.Size = 8
.Top = 5
.Left = 706.899
.Width = 179.735
.Height = 336.681
End With
End With
End Sub
Sub kopieergrafiek()
ActiveSheet.ChartObjects("Grafiek 4").Copy
End Sub
(including the suggestion in the comment below my post)
I does not seem to work. Does worksheet_change event perhaps works better?
edit 4:
I still do not have a solution for this issue. It already happens when the name of 1 of the legend items is to long to fit the space. And it also happens when there are to many items in the legend to fit in the space available.
I think there is no solution for this. Unless I could somehow tell excel to maximize the number of items in the legend. or to maximize the length of the series name.
I was having this problem myself with the legend resizing the plot area. I tried what Portland Runner suggested, only setting .Legend.IncludeInLayout to false (thus separating the legend from the plot area as he suggested, perhaps he made a typo?) and my plot area was no longer resized.
I also had this problem and found this answer. I found a fix that works for me. Not sure why exactly it works but I do these steps:
Set the legend position
Undock the legend (legend.includeLayout = false)
Resize the plot area to the size I wanted
Re-dock the Legend (legend.includeLayout = True)
Set the Legend.Left position
and after that the legend is correctly positioned and lined up.
I know this is an old thread, but since I had the same issue and was able to solve it, but did not really find the correct answer on this thread, I thought it would be good to post my solution. It is really important to refresh the pivotlayout, otherwise you will not see a difference in the Chart Legend. This will adjust the Legend so it will not overlap the plot area. It will also increase the size of the chart, so if you do not want that, you will need to use other code.
Sub AdjustChartLegendActiveSheet()
Dim j
For j = 1 To ActiveSheet.Shapes.count
If ActiveSheet.Shapes(j).Type = msoChart Then
ActiveSheet.Shapes(j).chart.Legend.IncludeInLayout = True
ActiveSheet.Shapes(j).chart.PivotLayout.PivotTable.PivotCache.Refresh
End If
Next j
End Sub
I have stacked bar chart in which the number of columns is dynamic, can change from 1 to n columns. I want the spacing between the charts and width of the bar to be consistent. How do I fix it. Please suggest solutions / ideas.
In a Stacked Bar chart, you can change the spacing between bars using
CategoryAxis.setLowerMargin
CategoryAxis.setMargin and
CategoryAxis.setUpperMargin
Code is below
protected JFreeChart generateGraph() {
CategoryAxis categoryAxis = new CategoryAxis("Categories");
categoryAxis.setLowerMargin(.01);
categoryAxis.setCategoryMargin(.01);
categoryAxis.setUpperMargin(.01);
categoryAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_90);
ValueAxis valueAxis = new NumberAxis("Values");
StackedBarRenderer renderer = new StackedBarRenderer();
renderer.setBarPainter(new StandardBarPainter());
renderer.setDrawBarOutline(false);
renderer.setShadowVisible(false);
renderer.setBaseItemLabelsVisible(true);
renderer.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator());
CategoryPlot plot = new CategoryPlot( _dataset,
categoryAxis,
valueAxis,
renderer);
plot.setOrientation(PlotOrientation.VERTICAL);
JFreeChart chart = new JFreeChart( "Title",
JFreeChart.DEFAULT_TITLE_FONT,
plot,
true);
//ChartFactory.getChartTheme().apply(_chart);
return chart;
}
StackedBarRenderer devotes some effort to making the "spacing between the [bars] and width of the bar to be consistent." It's not clear what you want it to do differently as the number of columns changes. The relevant geometry is determined by the parent BarRenderer in such methods as calculateBarWidth(), which can be overridden as desired. Also, verify that there is a value for each category in each series.
I have an excel sheet that contains two rectangles and text in other cells.
I need to allow users to only edit the text in the rectangle. They should not be able to change the size of the object.
Applying lock on the rectangle locks the object as well as the text.
Does anyone know how I can achieve this?
Why not create two objects, one being a rectangle that is locked, and one being a text box that is not locked? This is really simplistic, but a possible answer.
Another idea would be to have the rectangle equal a set cell, and let them enter their text in the cell and it would transfer over even when the rectangle is locked.
As far as I am aware Excel does not accommodate Events for shapes and so there is no simple way of detecting a change in a shape size and then resizing the shape.
It is possible to emulate what you are asking for by using a workaround.
Imagine you have two rectangles on your spreadsheet called 'Rectangle 1 and 'Rectangle 2'. When a user finishes updating the text in any given box they must then click the spreadsheet to move out of 'edit' mode for the shape. You can detect this using the Workbook_SheetSelectionChange event.
The following module allows you to set the size of the rectangles as constants and will resize the rectangles accordingly:
Const Rect1Height As Integer = 50
Const Rect1Width As Integer = 200
Const Rect2Height As Integer = 50
Const Rect2Width As Integer = 200
Sub SetRectangleSize()
Dim Rect1 As Shape
Dim Rect2 As Shape
Set Rect1 = ActiveSheet.Shapes("Rectangle 1")
Set Rect2 = ActiveSheet.Shapes("Rectangle 2")
Rect1.Height = Rect1Height
Rect1.Width = Rect1Width
Rect2.Height = Rect1Height
Rect2.Width = Rect1Width
End Sub
Now all you need to do is to call this sub from a workbook level event:
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
SetRectangleSize
End Sub
Each time a user updates the text in one of the rectangles they will click back on the spreadsheet and the event is fired, resulting in the rectangles being sized according to the constant height and width parameters that you have defined.