半角チルダ

ExcelVBA、その他。
覚え書きや、補足資料などのスクラップブック。
end-u(1037781)

■VBAでグラフの元データ範囲を取得

2009-12-22 21:00:00 | VBA Tips
■散布図のデータ ポイントにラベルを追加する の応用な話です。

まずは Sub pre() でサンプルチャート作成。
#ちょっとややこしい事してるのは、2003 and 2007に対応させるため。サンプルなのであまり気にしない :D
Sub pre()
  'サンプルデータシート追加し、2系列バブルチャートを作成
  Dim ws As Worksheet
  Dim r As Range
  Dim s As String
  Dim i As Long
  Dim v(0 To 4) As String

  Set ws = Sheets.Add
  s = "'" & ws.Name & "'!"
  ws.Range("A1").Value = "a"
  ws.Range("A6").Value = "b"
  ws.Range("B1:D11").Formula = "=int(rand()*100)"
  With ws.ChartObjects.Add(ws.Range("E1").Left, 0, 250, 200).Chart
    .HasLegend = False
    .ChartType = xlColumnClustered
    .SetSourceData ws.Range("B1:C1"), PlotBy:=xlColumns
    .ChartType = xlBubble3DEffect
    With .SeriesCollection
      For i = .Count To 1 Step -1
        .Item(i).Delete
      Next
      v(0) = s & "R1C1"
      v(1) = s & "R1C2:R5C2"
      v(2) = s & "R1C3:R5C3"
      v(3) = 1
      v(4) = s & "R1C4:R5C4"
      .NewSeries.FormulaR1C1 = "=SERIES(" & Join(v, ",") & ")"
      v(0) = s & "R6C1"
      v(1) = "(" & s & "R6C2:R9C2," & s & "R11C2)"
      v(2) = "(" & s & "R6C3:R9C3," & s & "R11C3)"
      v(3) = 2
      v(4) = "(" & s & "R6C4:R9C4," & s & "R11C4)"
      .NewSeries.FormulaR1C1 = "=SERIES(" & Join(v, ",") & ")"
    End With
  End With

  Set ws = Nothing
End Sub


(実行後のサンプル)


作成されたチャートを選択して実行です。
Sub test()
  Dim filed() As String
  Dim ret()  As String
  Dim v()   As String
  Dim s()   As String
  Dim cnt   As Long
  Dim cx   As Long
  Dim ub   As Long
  Dim n    As Long
  Dim i    As Long
  Dim j    As Long
  Dim k    As Long
  Dim buf

  If ActiveChart Is Nothing Then
    MsgBox "グラフを選択して実行"
    Exit Sub
  End If

  '項目名セット
  filed() = Split("name category_labels values order size")
  With ActiveChart
    'BubbleChartの時
    If (.ChartType = xlBubble) Or (.ChartType = xlBubble3DEffect) Then
      cx = 4
    Else
      cx = 3
    End If

    'アドレス文字格納配列サイズ決定
    cnt = .SeriesCollection.Count
    ReDim ret(0 To cnt, 0 To cx) As String
    For i = 0 To cx
      ret(0, i) = filed(i)
    Next

    '系列をLoop
    For i = 1 To cnt
      v = Split(.SeriesCollection(i).Formula, ",")
      ub = UBound(v)
      '右端の")"を除外
      v(ub) = Left$(v(ub), Len(v(ub)) - 1)
      '左端の"=SERIES("除外
      ret(i, 0) = Mid$(v(0), 9)
      n = 1
      For j = 1 To cx
        '隔範囲のアドレスを考慮
        If Left$(v(n), 1) = "(" Then
          ReDim s(1 To ub) As String
          For k = 1 To ub
            s(k) = v(n)
            n = n + 1
            If Right$(s(k), 1) = ")" Then Exit For
          Next
          ReDim Preserve s(1 To k)
          ret(i, j) = Join(s, ",")
        Else
          ret(i, j) = v(n)
          n = n + 1
        End If
      Next
      buf = Application.Index(ret, i + 1, 0)
      MsgBox "系列 " & i & vbLf & vbLf & Join(buf, vbLf)
    Next
  End With
  '新規シートに書き出す時。
  'Sheets.Add.Range("A1").Resize(cnt + 1, cx + 1).Value = ret
  Erase s
  Erase ret
End Sub


結果はこんな感じ。
系列 1
name       Sheet1!$A$1
category_labels Sheet1!$B$1:$B$5
values      Sheet1!$C$1:$C$5
order      1
size       Sheet1!$D$1:$D$5

系列 2
name       Sheet1!$A$6
category_labels (Sheet1!$B$6:$B$9,Sheet1!$B$11)
values      (Sheet1!$C$6:$C$9,Sheet1!$C$11)
order      2
size       (Sheet1!$D$6:$D$9,Sheet1!$D$11)
Comment
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

■Filter状態での可視セルから可視セルへのコピー

2009-12-02 21:00:00 | 雑記
オートフィルタやフィルタオプションでデータ抽出し、ある列の表示部分(可視セル範囲)を別の列の可視セル範囲へコピーしたい、つまり横へそのままスライドした位置関係でコピーしたい場合があるとします。

通常の[コピー]-[貼り付け]操作では、非表示部分に貼り付けられたり、『そのコマンドは複数の選択範囲に対して実行できません』のエラーになったりします。

そこで、列の非表示を利用してFillRightやFillLeftメソッドを使うと良いです。
■AutoFilter FilterModeでのFillRightメソッドの応用になりますね。

まずサンプルシート作成。
Sub pre()
  With Sheets.Add
    With .Range("A1")
      .Value = "f1"
      .AutoFill .Resize(, 6)
    End With
    With .Range("B2:F10")
      .Formula = "=int(rand()*10)"
      .Value = .Value
    End With
    .Range("4:4,7:7").ClearContents
    .Range("A4,A7,A11").Value = 1
    .Range("D4,D7").FormulaR1C1 = "=SUM(R[-2]C:R[-1]C)"
    .Range("D11").FormulaR1C1 = "=SUM(R[-3]C:R[-1]C)"
    .Range("A1").CurrentRegion.AutoFilter 1, 1
    .Range("D2:D11").Interior.Color = vbYellow
    .ShowAllData
  End With
End Sub

Sub pre()実行後。


A列の値が 1 で抽出した後のD列をF列にコピーします。(色付けしたセル)
Sub test1()
  With ActiveSheet
    .Range("A1").CurrentRegion.AutoFilter 1, 1
    .Columns("E").Hidden = True
    .Range("D2:F11").FillRight
    .Columns("E").Hidden = False
    .ShowAllData
  End With
End Sub

同じく、D列をB列にコピーします。
Sub test2()
  With ActiveSheet
    .Range("A1").CurrentRegion.AutoFilter 1, 1
    .Columns("C").Hidden = True
    .Range("B2:D11").FillLeft
    .Columns("C").Hidden = False
    .ShowAllData
  End With
End Sub

実行後。


こんな感じで、非表示セルに影響与えず、可視セル間のコピーができます。

ぁ、別にマクロでなく、手作業で可能です。
フィルタ抽出状態で、対象外の列を非表示にして、コピー元とコピー先を隣接させて選択します。
その後[編集]-[フィル]-[右方向へコピー]です。ショートカットキーは[Ctrl]+[r]。
左列へコピー、.FillLeftメソッドは[編集]-[フィル]-[左方向へコピー]です。

または、コピー元とコピー先を隣接させた後、コピー元だけ選択してフィルハンドルを右あるいは左へドラッグ。...という操作でも同じ結果になります。
Comment
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

■条件付書式。数式はR1C1形式で。(検証編)

2009-12-01 22:00:00 | 雑記
昨日の記事が少しぶっきらぼうだったので、補足。
それにmoug.netのログが消えたら意味がわからないでしょうし。

結論から簡単に書くと、
『VBAで条件付書式を設定する時、その条件がセルアドレスを参照する数式条件の場合は、コード実行時のActiveCellの位置によって数式条件のセルアドレスが相対的に変化してしまう。
∴条件付書式を設定する範囲の基点セルをSelectして実行するか、数式をR1C1形式で記述する。
(R1C1形式で設定する場合はSelect不要)』
という事です。

まずテストコード全掲載。
Option Explicit
Const KITEN = "B2" 'テスト範囲基点のアドレス
'---------------------------------------------------------------------
Sub pre()
  Dim r As Range
  Dim f As Boolean

  f = True
  With Sheets(1)
    For Each r In .Range(KITEN).Resize(5, 5)
      If f Then r.Value = 1
      f = Not f
    Next
  End With
End Sub
'---------------------------------------------------------------------
Sub test1()
  Dim r As Range

  With Sheets(1)
    Set r = .Range(KITEN)
    r.Offset(1).Select
    With r.Resize(5, 5).FormatConditions
      .Delete
      .Add(Type:=xlExpression, Formula1:="=" & KITEN & "=1" _
        ).Interior.ColorIndex = 6
    End With
  End With
  Debug.Print "test1_1", r.FormatConditions(1).Formula1
  r.Select
  Debug.Print "test1_2", r.FormatConditions(1).Formula1

  Set r = Nothing
End Sub
'---------------------------------------------------------------------
Sub test2()
  Dim r As Range

  With Sheets(1)
    Set r = .Range(KITEN)
    r.Offset(1).Select
    With r.Resize(5, 5).FormatConditions
      .Delete
      .Add(Type:=xlExpression, Formula1:="=RC=1" _
        ).Interior.ColorIndex = 6
    End With
  End With
  Debug.Print "test2_1", r.FormatConditions(1).Formula1
  r.Select
  Debug.Print "test2_2", r.FormatConditions(1).Formula1

  Set r = Nothing
End Sub
'---------------------------------------------------------------------
Sub test3()
  Dim r  As Range
  Dim ref As Long

  With Application
    ref = .ReferenceStyle
    .ReferenceStyle = xlR1C1
  End With
  With Sheets(1)
    Set r = .Range(KITEN)
    r.Offset(1).Select
    With r.Resize(5, 5).FormatConditions
      .Delete
      .Add(Type:=xlExpression, Formula1:="=RC=1" _
        ).Interior.ColorIndex = 6
    End With
  End With
  Debug.Print "test3_1", r.FormatConditions(1).Formula1
  r.Select
  Debug.Print "test3_2", r.FormatConditions(1).Formula1
  Application.ReferenceStyle = ref

  Set r = Nothing
End Sub

Sub pre()実行後。


基点セルから5x5の範囲に条件付書式を設定します。
Sub test1()実行後。


本当は『=自アドレス=1』の数式条件を満たすセルに色づけしたいのですが、
r.Offset(1).Select
しているために、基点セルB2の数式条件がずれてしまいます。


(Offsetせず、基点rをSelectすればずれません)

Selectしたくない、もしくはSheetをActiveにしたくない場合、数式をR1C1形式にします。
Sub test2()実行後。


ActiveCellの位置関係なく、数式条件が正しく設定されます。


ついでに。
条件付書式で設定された条件内の数式を取得したい場合もActiveCellとの相対位置によって数式が変化します。
これは数式をR1C1形式で記述したtest2でも同様です。
Debug.Print "test2_1", r.FormatConditions(1).Formula1
r.Select
Debug.Print "test2_2", r.FormatConditions(1).Formula1
この部分。結果は
test2_1    =B3=1
test2_2    =B2=1
同じ r の条件が変化しています。
これを、ActiveCell位置に関係なく取得したい場合は、Applicationのアドレス参照形式をR1C1形式に変更します。
Sub test3()での
With Application
  ref = .ReferenceStyle
  .ReferenceStyle = xlR1C1
End With
この部分。(後で戻しています)

test1からtest3まで実行したイミディエイトウィンドウの結果は
【2003の場合】
test1_1    =B2=1
test1_2    =B1=1
test2_1    =B3=1
test2_2    =B2=1
test3_1    =RC=1
test3_2    =RC=1
こうなります。

ちなみに、
【2007の場合】
test1_1    =B1=1
test1_2    =B1=1
test2_1    =B2=1
test2_2    =B2=1
test3_1    =B2=1
test3_2    =B2=1
2007では条件取得時のアドレスの変化については改善されているようです。

こういった事象に対する質疑って、Q&A掲示板ではあまり見かけませんが、VBAで条件付書式を設定する時のセオリーのようですね。
『Excelノート 6-1 書式 14 マクロで条件付書式(数式)を設定するには?』
http://park11.wakwak.com/~miko/Excel_Note/06-01_shoshiki.htm#06-01-14

さらに深い過去ログ
『条件付書式の数式の評価について』
http://www.keep-on.com/excelyou/1999lng4/199909/99090110.txt
『条件付書式による色をVBAから取得するには?』
http://www.keep-on.com/excelyou/2000lng4/200005/00050350.txt

#こういった情報があると、やっぱり過去ログって先人の経験と知恵が詰まったおタカラだよなぁって思います。
#それを探り当てる検索エンジンも凄いっ...てのも言えるかもしれませんけどね :D
Comment
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする