2017-02-20 36 views
1

У меня есть код, который получает данные с листа и создает график. В исходном листе каждый столбец представляет собой серию, и число серий может меняться.Динамическая ссылка на UsedRange в VBA

Что делает мой код: он считывает используемые диапазоны, чтобы он мог графически отображать значения.

Obs1: Для 2 временных рядов я создаю, данные в годовом исчислении, так как я считать в обратном порядке для расчета, если данные, полученные до менее чем один год, код показывает, как «Недостаточно данных» ,

Проблема: Если я запускаю код с 2 временными рядами (2 столбца), я получаю две строки в диаграммах. Но если я затем удалю одну из серий и запустил ее снова, я получу одну строку со значениями и вторую пустую строку в диаграмме.

Вопрос: Как решить эту проблему?

Что я уже пробовал: Я пытаюсь изменить способ ссылки на диапазоны, чтобы он повторно запускал код, он возвращает на график только строки, имеющие значения. Проблема в том, что я не могу найти способ правильно ссылаться на такой диапазон.

Соответствующая часть кода:

Function Grapher(ChartSheetName As String, SourceWorksheet As String, ChartTitle As String, secAxisTitle As String) 

Dim lColumn As Long, lRow As Long 
Dim LastColumn As Long, LastRow As Long 
Dim RetChart As Chart 
Dim w As Workbook 
Dim RetRange As Range 
Dim chrt As Chart 
Dim p As Integer 
Dim x As Long, y As Long 
Dim numMonth As Long 
Dim d1 As Date, d2 As Date 
Dim i As Long 

Set w = ThisWorkbook 

'find limit 
LastColumn = w.Sheets(SourceWorksheet).Cells(1, w.Sheets(SourceWorksheet).Columns.Count).End(xlToLeft).column 
LastRow = w.Sheets(SourceWorksheet).Cells(w.Sheets(SourceWorksheet).Rows.Count, "A").End(xlUp).Row 

'check for sources that do not have full data 
'sets the range 
i = 3 
If SourceWorksheet = "Annualized Ret" Or SourceWorksheet = "Annualized Vol" Then 

    Do While w.Worksheets(SourceWorksheet).Cells(i, 2).Text = "N/A" 

     i = i + 1 

    Loop 

'##### this is the part I believe is giving the problem: 
    '##### the way to reference the last cell keeps getting the number of columns (for the range) from the original column count. 

    Set RetRange = w.Worksheets(SourceWorksheet).Range(w.Worksheets(SourceWorksheet).Cells(i, 1), w.Worksheets(SourceWorksheet).Cells.SpecialCells(xlLastCell)) '**************** 

Else 

    Set RetRange = w.Sheets(SourceWorksheet).UsedRange 

    'Set RetRange = w.Sheets(SourceWorksheet).Range("A1:" & Col_Letter(LastColumn) & LastRow) 

End If 

''''''''''''''''''''''' 

For Each chrt In w.Charts 
    If chrt.Name = ChartSheetName Then 
     Set RetChart = chrt 
     RetChart.Activate 
     p = 1 
    End If 
Next chrt 

If p <> 1 Then 
    Set RetChart = Charts.Add 
End If 

'count the number of months in the time series, do the ratio 
d1 = w.Sheets(SourceWorksheet).Range("A2").Value 
d2 = w.Sheets(SourceWorksheet).Range("A" & LastRow).Value 

numMonth = TestDates(d1, d2) 

x = Round((numMonth/15), 1) 

'ratio to account for period size 
If x < 3 Then 
    y = 1 
ElseIf x >= 3 And x < 7 Then 
    y = 4 
ElseIf x > 7 Then 
    y = 6 
End If 

'create chart 
     With RetChart 
      .Select 
      .ChartType = xlLine 
      .HasTitle = True 
      .ChartTitle.Text = ChartTitle 
      .SetSourceData Source:=RetRange 
      .Axes(xlValue).MaximumScaleIsAuto = True 
      .Axes(xlCategory, xlPrimary).HasTitle = True 
      .Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = "Date" 
      .Axes(xlValue, xlPrimary).HasTitle = True 
      .Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = secAxisTitle 
      .Name = ChartSheetName 
      .SetElement (msoElementLegendBottom) 
      .Axes(xlCategory).TickLabelPosition = xlLow 
      .Axes(xlCategory).MajorUnit = y 
      .Axes(xlCategory).MajorUnitScale = xlMonths 

'sets header names for modified sources 
      If SourceWorksheet = "Drawdown" Then 
       For lColumn = 2 To LastColumn 

        .FullSeriesCollection(lColumn - 1).Name = "=DD!$" & Col_Letter(lColumn) & "$1" 
        .FullSeriesCollection(lColumn - 1).Values = "=DD!$" & Col_Letter(lColumn) & "$3:$" & Col_Letter(lColumn) & "$" & LastRow 

       Next lColumn 

      ElseIf SourceWorksheet = "Annualized Ret" Then 
       For lColumn = 2 To LastColumn 

        .FullSeriesCollection(lColumn - 1).Name = "='Annualized Ret'!$" & Col_Letter(lColumn) & "$1" 

       Next lColumn 

      ElseIf SourceWorksheet = "Annualized Vol" Then 
       For lColumn = 2 To LastColumn 

        .FullSeriesCollection(lColumn - 1).Name = "='Annualized Vol'!$" & Col_Letter(lColumn) & "$1" 

       Next lColumn 

      End If 

     End With 

End Function 

Obs2: Мой код в настоящее время функционал (есть некоторые функции, я не добавил, так, чтобы не тратить больше места).

Obs3: Это проблема, когда я уменьшить число столбцов (ряды данных): enter image description here

+0

Вы пробовали превращение данных в таблицу, а затем график должен автоматически регулировать, как изменяются данные? – SJR

+0

@SJR Нет. Упоминайте, как это сделать? – DGMS89

+1

@ DGMS89: https://support.office.com/en-us/article/Overview-of-Excel-tables-7ab0bb7d-3a9e-4b56-a3c9-6c94334e492c Это должно объяснить многое, и, вкратце, таблица Excel умные объекты ('ListObjects' в VBA), которые будут расширяться, если вы добавите данные в следующую доступную строку после таблицы, и поэтому должны помочь с вашей проблемой! ;) – R3uK

ответ

0

Так как я не мог найти лучшего, более элегантный способ подойти к этой проблеме (даже таблицы, где уступая ту же ошибку), я исправил, явно удалив лишнюю серию в конце, основываясь на их именах.

Обс: Если в серии не было данных, новый вставленный код изменит это название серии на один из приведенных ниже и полностью удалит эту серию.

код будет добавлен к концу:

'deleting the extra empty series 
     Dim nS As Series 
     'this has to be fixed. For a permanent solution, try to use tables 
     For Each nS In RetChart.SeriesCollection 
      If nS.Name = "Series2" Or nS.Name = "Series3" Or nS.Name = "Series4" Or nS.Name = "Series5" Or nS.Name = "Series6" Or nS.Name = "Series7" Or nS.Name = "Series8" Or nS.Name = "" Then 
       nS.Delete 
      End If 
     Next nS