Excel VBA高级图表操作

我在使用VBA的Excel中对图表的高级操作有一个非常特殊的问题。

我想尝试在这个截图的基础上解释它。

我的图表

对于我的理解和经过几个小时的文学和networking研究,没有办法在绘制图表时产生可比的和恒定的结果,因为有几个属性是不能操作的,有些命令不能正确执行。 我使用VBA将两个图表的绘图区域的宽度设置为700(手动生成图表之后):

ActiveChart.PlotArea.Width = 700 

之后,一个宽度是698.12,一个是712.34(比较小区的右端)。 此外,根据y轴刻度的最大值(80与100),绘图区域的左边界是可变的。 这些问题的结果是情节不一致。

为什么这对我至关重要? 那么,想象一下,你有一个Excel计算工具,用于项目预测等。这是由几个部门,如贵公司的人使用,因此应始终看起来相同,并可比较。 这些预测的一部分是一个应该在图表中可视化的容量规划。 由于这些项目具有不同的里程碑,例如不同的项目阶段,这些图表应显示代表这些阶段的条形图。 使用辅助轴将不起作用,因为无法将其与主要主轴同步以使其看起来不错。 总是有一个偏移量。 所以计划是在这些图表中绘制graphics。 要做到这一点,以我的理解,我需要绘图区域和列等的确切位置,来计算这些条形和其他形状的相对位置。

我希望我的解释足以让你知道我要做什么。 所以我会回到我的问题:

为什么Excel在每种情况下都不同地解释我的命令(绘图区宽度)? 是否有可能修复/定义的阴谋面积肯定? 是否有更多的可操作的对象/属性比logging在msdn和其他来源,我发现迄今为止,我如何得到这些?

我期待着你的回复。

编辑:

正如RBarryYoung所问,我写了一些代码,以便重现问题。 当然,这次不同右边界的问题没有出现。 但是,至lessy轴的宽度和因此绘图区域的可变宽度(例如绘图区域的左边界的可变位置)的问题是可重现的。 如果你自己画一些线,你会看到,左边界,因此列本身是抵消。

 Sub DrawChart() Dim wkb As Workbook Dim wks As Worksheet Dim chart1 As Chart Dim chart2 As Chart Dim table1 As ListObject Dim table2 As ListObject Dim r1 As Range Dim r2 As Range Set wkb = ThisWorkbook Set wks = wkb.Sheets(1) With wks .Cells(1, 1).Value = "Date" .Range(.Cells(1, 2), .Cells(1, 10)).Formula = "=today()+column()" .Cells(2, 1).Value = "Budget" .Range(.Cells(2, 2), .Cells(2, 10)).Formula = "=5*column()" .Cells(4, 1).Value = "Date" .Range(.Cells(4, 2), .Cells(4, 10)).Formula = "=today()+column()" .Cells(5, 1).Value = "Budget" .Range(.Cells(5, 2), .Cells(5, 10)).Formula = "=20*column()" Set table1 = .ListObjects.Add(SourceType:=xlSrcRange, Source:=Range(Cells(1, 1), Cells(2, 10)), xllistobjecthasheaders:=xlYes) table1.Name = "table1" Set table2 = .ListObjects.Add(SourceType:=xlSrcRange, Source:=Range(Cells(4, 1), Cells(5, 10)), xllistobjecthasheaders:=xlYes) table2.Name = "table2" Set r1 = Range(.Cells(7, 2), .Cells(17, 15)) Set r2 = Range(.Cells(34, 2), .Cells(44, 15)) Set chart1 = .ChartObjects.Add(r1.Left, r1.Top, r1.Width, r1.Height).Chart With chart1 .ChartType = xlColumnStacked .SetSourceData Source:=Range("table1[#All]"), PlotBy:=xlRows .HasLegend = False .ChartArea.Height = 320 .ChartArea.Width = 620 .PlotArea.Height = 300 .PlotArea.Width = 600 End With Set chart2 = .ChartObjects.Add(r2.Left, r2.Top, r2.Width, r2.Height).Chart With chart2 .ChartType = xlColumnStacked .SetSourceData Source:=Range("table2[#All]"), PlotBy:=xlRows .HasLegend = False .ChartArea.Height = 320 .ChartArea.Width = 620 .PlotArea.Height = 300 .PlotArea.Width = 600 End With End With End Sub 

如果我理解正确,你想build立像这样的同步图表: 同步散点图线图

基于散点图types的同步图表是使用OpenXML SDK和C ++ / CLI生成的。 但你的情况的方法应该是一样的。

此外,根据y轴刻度的最大值(80与100),绘图区域的左边界是可变的。

PloatArea利润率由Excel控制。 因此,如图所示,由于PlotArea会自动更改大小,所以在绘图上分配足够的空间以放置值轴的刻度标签,而不pipe宽度或高度如何。 在此之前,相同的最小值/最大值,相对轴位置和时间点位置已经在每张图表上同步。 标题和图例被禁用,以防止意外alignment,如你的代码示例。

为了在VBA中同步PlotArea的水平放置,使用InsideLeft和InsideWidth属性如下:

 Sub test_synch() With ActiveSheet synch_plot_areas .ChartObjects(1), .ChartObjects(2) End With End Sub Sub synch_plot_areas(ByVal ch1 As ChartObject, ByVal ch2 As ChartObject) Dim v_min As Double, v_max As Double, v_delta As Double 'Align left v_min = ch1.Left: If v_min > ch2.Left Then v_min = ch2.Left ch1.Left = v_min: ch2.Left = v_min 'Synchronization of external chart object width v_min = ch1.Width: If v_min > ch2.Width Then v_min = ch2.Width ch1.Width = v_min: ch2.Width = v_min 'Margins is controlled by Excel 'Hence .InsideWidth is sychnronized first to minimum to prevent PlotArea's constraints on margins and placement v_min = ch1.Chart.PlotArea.InsideWidth: If v_min > ch2.Chart.PlotArea.Width Then v_min = ch2.Chart.PlotArea.InsideWidth With ch1.Chart.PlotArea v_delta = .InsideWidth - v_min .Width = .Width - v_delta End With With ch2.Chart.PlotArea v_delta = .InsideWidth - v_min .Width = .Width - v_delta End With '.Left is sychnronized second by maximum margin: now there is enough space for Value axis on both charts v_max = ch1.Chart.PlotArea.InsideLeft: If v_max < ch2.Chart.PlotArea.InsideLeft Then v_max = ch2.Chart.PlotArea.InsideLeft With ch1.Chart.PlotArea v_delta = v_max - .InsideLeft .Left = .Left + v_delta End With With ch2.Chart.PlotArea v_delta = v_max - .InsideLeft .Left = .Left + v_delta End With End Sub 

在PlotArea同步之前: synch_PlotArea_before

在使用test_synchmacros的PlotArea同步之后: synch_PlotArea_after