Excel charts are placed on different positions depending on screen resolution - excel

I am creating some charts with VBA. Target is to position them at the upper left corner of a cell (here as range rgCht) with a size of 16 rows x 9 columns.
Here is the code:
' Calculate active cell to place the chart
Set rgCht = wsGr.Cells(i * 17 + 2, 2)
Set cht = wsGr.ChartObjects.Add( _
Left:=rgCht.Left, _
Width:=rgCht.Width * 9, _
Top:=rgCht.Top, _
Height:=rgCht.Height * 16)
The result is that if the sheet is displayed on my notebook screen while the macro runs, all charts are placed and sized properly. However when I run it on a bigger screen, the charts are shifted 1 unit per row down, i. e. in line 70 I have 7 units difference between the calculated position and the real position on the sheet:
The line height is 14.5 units, so in row 70 the top position is 1000.5 . However when I manually move the chart to the top left corner of the cell and check the coordinates, I get 993.5.
I'm running out of ideas. Any hint is appreciated.
Both monitors run with a resolution of 1920x1080. Only difference is that the scaling is 125% on the big screen and 150% on the small one.

Related

Excel 2016 and newer VBA: how to maximize a chart within/to the worksheet size?

In https://i.stack.imgur.com/s6gII.png and How to get the size (width and height) of the area with excel vsto c# excluding the ribbon area? a similar question has already been put.
Excluding all GUI elements outside/around the "inner/client" worksheet area, e.g. without the ribbon, "X/ok/fx" + cell contents, Sheet menu, "Ready + Record Macro" footer line + frame heights, left + right border + frame widths, etc.
And together with How to get the screen position of an active workbook? neither of these links has answered my needs yet. Or their instructions do not work for me, because neither of the .PageSetup.*Margin values corresponds to my worksheet "inner/client" OR "outside/GUI" borders + frames + overhead sizes.
I know, by writing
With ActiveChart.Parent 'access the chart container = the Shape
.Left = 0
.Top = 0
.Width = 4 * 72 'fixed size example
.Height = 3 * 72 'fixed size example
End With
I can set the chart position + size, in this example to a fixed size of 3 * 4 inches.
But HOW TO GET/fetch the whole currently visible dynamic worksheet "inner/client" size (at least once a method call) ?
In order to set the chart size, so that it covers/uses the whole currently visible dynamic worksheet "inner/client" size (at least once a method call). Hopefully: nothing more (no scrollbars shifting needed to see the whole chart), nothing less (no unneccessary "tiny" chart) ?
[I know, that size assignment will work for me only "for a moment" until a workbook resize happens. So I'll have to adjust the chart size again (and again (and again ...)), e.g. by using a timer (or a system timer). Or is there some "anchor/chain/nail" chart property, so that it ALWAYS keeps up with the "inner/client" worksheet size (within the workbook) ?]
Thanks for your help
This is about as good as you can do.
Sub SizeChartToWindow()
Dim VisibleRange As Range
Set VisibleRange = ActiveWindow.VisibleRange
Dim UsableRange As Range
Set UsableRange = VisibleRange.Resize(VisibleRange.Rows.Count - 1, _
VisibleRange.Columns.Count - 1)
With ActiveChart.Parent
.Left = UsableRange.Left
.Top = UsableRange.Top
.Width = UsableRange.Width
.Height = UsableRange.Height
End With
End Sub
Many thanks, that helped me a lot.
This also takes care of the worksheet scrollbars "scrolled away", wonderful.
And the right + bottom remainder of 0.00 .. 0.99 * cell sizes is "good enough" (and I have reduced the cell width to match the cell height = 20 pixels in order to reduce that remainder effect).
:)))

Centering shape in Cell increases height from top as row increases

I have a macro that is taking information from another sheet and reformating. Every 5th row down there should be an image and all other information is entered correctly in the following rows. As the row number increases it is increasing distance from the top of the cell to the image. For example, if the first shape is 5 pixels from the top of the designated cell, the next will be 6 and so forth. If it was a simple trend I could add a variable to accommodate this, but all images are slightly different in size thus why I am trying to do this dynamically.
So far, as mentioned above, I have tried doing this statically by using a variable to account for the increase, but to no success. Below is the code I am currently using that does not seem to be working.
If CopyPicFromCell(shtSource.Range("A1").Offset(i - 1, 2)) Then
'copied the picture, so paste to shtDest
shtDest.Paste
With shtDest.Shapes(shtDest.Shapes.Count)
.Top = shtDest.Range("A1").Offset(x - 3, 0).Top + ((shtDest.Range("A1").Offset(x - 3, 0).Height - .Height) / 2)
.Left = shtDest.Range("A1").Offset(x - 3, 0).Left + (shtDest.Range("A1").Offset(x - 3, 0).Width - .Width) / 2
End With
End If
This always centers the image left to right but does not seem to be doing the trick vertically. Please inform if there is any other information needed. Thanks!

Zoom couple of columns to fit page with VBA

I'm having trouble fitting my columns in Excel on a sheet.
I have a sheet with columns from A to CK (can be different per project).
I don't need to print column A, but column B has to be on all pages and next to column B has to be 3 columns. So that will make column "B,C:E" on first page, next page "B,F:H", and so on... Column B is set as title, so it will be printed on every page.
My problem is to set the scale. What I'm doing:
Take pagesize and translate to points, take off margin left and margin right = my printable area
Get the width of range("B:E") = my range to fit the page
Divide my printable area by my range to fit, multiply that with 100%, and extract 1% to make sure it will fit
The outcome in my situation is 83, but is has to be 77 to fit the page. I'll have to find other numbers I think, but I don't know how and which...
My code:
If ActiveSheet.Name = "Meterkastlijst" Then
Dim lngZoom As Long
Dim lngKolB As Long
Dim lngPagB As Long
lngKolB = ActiveSheet.Range("B:E").Width
If ActiveSheet.PageSetup.PaperSize = xlPaperA4 Then
lngPagB = CLng(Application.CentimetersToPoints(21)) - CLng((ActiveSheet.PageSetup.LeftMargin + ActiveSheet.PageSetup.RightMargin))
ElseIf ActiveSheet.PageSetup.PaperSize = xlPaperA3 Then
lngPagB = CLng(Application.CentimetersToPoints(29.7)) - CLng((ActiveSheet.PageSetup.LeftMargin + ActiveSheet.PageSetup.RightMargin))
End If
If lngPagB <> 0 And lngKolB <> 0 Then
lngZoom = ((lngPagB / lngKolB) * 100) - 1
With ActiveSheet.PageSetup
.Zoom = lngZoom
End With
End If
End If
Different widths:
Column B: 45 (319 pixels) -> in Excel, set with VBA
Column C: 15 (109 pixels) -> in Excel, set with VBA
Column D: 30 (214 pixels) -> in Excel, set with VBA
Column E: 20 (144 pixels) -> in Excel, set with VBA
Column B-E: 589 points -> with VBA
Page: 21 centimeters (595 points)
Margins (left & right): 1.8 centimeters (50.4 points)
Print area: 595 - 101 (100.8) = 494 points
With numbers above it calculates 83%, but then it doesn't fit, when I set it manually to 77% it does fit, but how can I get this number with VBA? I don't understand the column widths, what I see in Excel and how I set it in VBA (45+15+30+20) is different from what VBA tells me it should be (589)...
Column Width Units
Column width is measured in Characters, Points, Centimeters / Inches, Pixels, ...
Column width in Characters
If you set a column width by manual value input or by mouse, you see the "amount of standard font number characters". Please refer to Microsoft support for details.
This value can be read and written in VBA: .Range.ColumnWidth = 10.78.
The maximum value is 255.
Column width in Points
This is an internal value not shown in GUI during manual resize of a column.
It corresponds to 72 points per inch.
In VBA it can only be read: .Range.Width
Column width in Pixels
Excel shows the column width in pixels (in parentheses) during manual resize of a column width in normal view. This value can not be read or written directly in VBA.
Column width in Centimeters or Inches
During manual resize within the page layout view Excel shows column width in centimeters (or inches) instead of pixels.
Only this value depends on print zoom level!
The measurement unit itself can be read in VBA:
Application.MeasurementUnit ' 0 = xlInches, 1 = xlCentimeters, 2 = xlMillimeters
Conversion Formulas
By this you may check or verify all values in your environment:
Dim ScreenResolution As Double
Dim ColumnWidthChars As Double
Dim ColumnWidthPoints As Double
Dim ColumnWidthPixels As Double
Dim ColumnWidthInches As Double
Dim ColumnWidthCentimeters As Double
ScreenResolution = 120 ' normal (96 dpi) or large (120 dpi)
ColumnWidthChars = ActiveSheet.Columns(1).ColumnWidth
ColumnWidthPoints = ActiveSheet.Columns(1).Width
ColumnWidthPixels = (ColumnWidthPoints / 72) * ScreenResolution
ColumnWidthInches = ColumnWidthPoints / 72 * ActiveSheet.PageSetup.Zoom / 100
ColumnWidthCentimeters = ColumnWidthInches * 2.54
Debug.Print ColumnWidthChars, ColumnWidthPoints, ColumnWidthInches, _
ColumnWidthCentimeters, ColumnWidthPixels
ScreenResolution may be retrieved with API function GetDeviceCaps(hDC, 88)
Rounding Effects
Excel stores the character-based .Range.ColumnWidth with decimals for each relevant column in the workbook file. If you set it to 100, it is stored as e. g.
<cols><col min="1" max="1" width="100.77734375" customWidth="1"/></cols>
After reopening this file, the reported .ColumnWidth is 100 without decimals.
If you set a large column width and switch between normal view and page layout view, then you may register difference of about 2% between the measures (.Range.Width and pixels suddenly change) - but all values still correspond to each other according to above formulas.
Display Scaling Dependency
All different column width values are independent of Excel's view zoom level and/or Windows 10 display scaling.
Print Zoom Dependency
Only the inch- and centimeter values change, if you change the print zoom level.
But you get more or less columns i. e. amount of points on your paper.
Excel measures .PageSetup.Leftmargin in points (with a scale of 72 points per inch). This corresponds to .Range.Width which is also measured in points.
Example: If I set both paper margins to 5.5 cm, then the resulting A4 paper width of 10 cm holds e. g. two columns with a total .Width of appr. 283 points which corresponds to 72 points/inch.
If I set the print zoom to 83 percent a .Width of appr. 340 points is maximum, and at a print zoom of 30 % it's almost 943 points.
Print Scaling
The calculation of a print zoom factor is
WorkSheet.PageSetup.Zoom = (PageWidthInPoints / AllColumnsWidthInPoints) * 100
Your calculation seems to be correct, but I would subtract at least 2 % (see rounding effects above).

How to avoid "A Chart may only have up to 256 series" issue (Excel VBA)

I'm trying to build bubble chart from a scratch in excel. Below is piece of code I'm using. Everything works fine until SeriesCollection.NewSeries reaches 256. Then I'm getting error message: A Chart may only have up to 256 series.
Can you anybody help me, how to avoid this issue. Is there any more elegant solution? Thanks a lot for any of your hint or advice.
Source code for my bubble chart:
With wsAnalytics.ChartObjects.Add(Left:=0, Width:=995, Top:=0, Height:=580)
For i = 1 To Range("Config_BubbleChartData").Rows.Count
.Chart.SeriesCollection.NewSeries
.Chart.SeriesCollection(i).name = Range("Config_BubbleChartData").Rows(i).Cells(1, 1)
.Chart.SeriesCollection(i).XValues = Range("Config_BubbleChartData").Rows(i).Cells(1, 3)
.Chart.SeriesCollection(i).Values = Range("Config_BubbleChartData").Rows(i).Cells(1, 4)
Select Case BubbleColor
Case 1
.Chart.SeriesCollection(i).Format.Fill.ForeColor.RGB = RGB(255, 0, 0)
Case 2
.Chart.SeriesCollection(i).Format.Fill.ForeColor.RGB = RGB(0, 0, 255)
Case 3
.Chart.SeriesCollection(i).Format.Fill.ForeColor.RGB = RGB(0, 255, 0)
End Select
If i = 1 Then .Chart.ChartType = xlBubble3DEffect
.Chart.SeriesCollection(i).BubbleSizes = "=" & Range("Config_BubbleChartData").Parent.name _
& "!" & Range("Config_BubbleChartData").Rows(i).Cells(1, 5).Address(1, 1, xlR1C1)
Next i
You only need as many series as you have colors. Certainly you don't need more than 255 colors, since no human would be able to distinguish more than a dozen in a cluttered bubble chart.
Set up the data with four columns for X, Y, bubble size, and bubble color. Append another column for each color in the bubble color column, and use the color name as the column header. Use an IF formula in these columns to put the Y value for each color into the appropriate column.
In my example, I have X and Y in columns A and B, bubble size and color in C and D, plus the bubble color names in E1:G1. The formula in cell E2 is
=IF($D2=E$1,$B2,NA())
and I've filled this into E2:G16. The result is the Y value if the column header matches the color, and #N/A otherwise, which will not plot.
Select A2:C19 and create the bubble chart (top left chart).
Click the Select Data button on the Chart Tools > Design tab of the ribbon, select the only series in the chart, and Edit it, so cell E1 is used for the name, and E2:E16 is used for the Y values. Keep A2:A16 as the X values and C2:C16 as the bubble size. This series will have the default color for the first series, which in Excel 2013 and 2016 is blue (top right chart).
Stay in or return to the Edit Data dialog, and add a series. Use cell F1 for series name, A2:A16 as X values, F2:F16 as Y values, and C2:C16 as the bubble size. This series will use the default second color, orange (bottom left chart).
Add one more series, use cell G1 for series name, A2:A16 as X values, G2:G16 as Y values, and C2:C16 as the bubble size. This series uses the default third color, gray (bottom right chart).
Note that all series use the same X values and bubble sizes, but different Y values.

How to create a text based Y axis on excel chart

I wish to customized the Y-axis to text instead on value.
Is there any way I can do it without any plugin?
Here will be my data:
A B C D
1 Lower Limit Upper Limit # Data
2 30S 40S A1234 30A
3 30S 40S A2345 30S
4 30S 40S A1256 30S
I wish my Y axis will be 30S, 30A, 40A, 40S intead of 10,20,30,40
and my X axis will be A1234,A2345,A1256
Is there any possible that I can change the X axis value?
I started with your data, and I added a small lookup table. I inserted a column "Value" (blue text) in your data range that has the Y value corresponding to the label in your "Data" column. You can use a lookup formula for this, for example, the formula in D2 is:
=INDEX($H$2:$H$5,MATCH(E2,$I$2:$I$5,0))
I made a column chart (don't know what type of chart you want, but this technique is widely applicable) using the yellow shaded range in the first data range (top left chart). I selected and copied the green shaded range in the second data range, selected the chart, and used Paste Special to add the data to the chart, using the settings shown in the dialog overlying the top right chart.
This has added another set of columns (bottom left chart), not so useful. I right-clicked the added series, picked Change Series Chart Type from the pop-up menu, and changed just this series to an XY scatter type (bottom right chart).
The XY scatter series is on the secondary axis, also not too useful. I formatted the XY series, and changed the axis to Primary (top left chart below). The 0.5 values in column G make the points line up with the vertical axis of the chart.
I added data labels to the XY series, shown in orange to distinguish them from the black axis labels (top right chart below). I formatted the labels so they appear to the left of the points, and so they used the Value from Cells option, based on the labels in I2:I5 (middle left chart below). If you don't have Excel 2013, you don't have this option, but you could
Manually type the desired text into the labels.
Link each label to the desired cell: select the labels (one click), select the desired label (second click), type = in the formula bar, select the cell, press Enter, repeat for all labels.
Use a third-party add-in like Rob Bovey's free Chart Labeler from appspro.com.
I hid the default axis labels. You can select None for axis labels, and then resize the plot area to make room for the custom labels created above. But I used a custom number format for the axis, which consisted of several space characters enclosed in double quotes. See middle right chart below.
Finally I rescaled the vertical axis so its min and max were 0 and 40 and the major spacing was 10, I formatted the XY series to use no markers, and I changed the label font color back to Automatic (bottom chart).

Resources