いつもお世話になっております。
エクセルのグラフの範囲一括変更について教えてください。
以前、グラフ範囲を一括で変更かける方法をマクロにて伝授していただいたのですが
そのマクロは現時点で選択範囲が同じであれば「変更前」「変更後」を入力し一括で変更することが
出来るのですが(一発目はきちんと合っていたのに)最近範囲がバラバラになっていることに気が付きました。
現場の進み具合でその月の作業日数が3~4日増加するのでその為の対応なのかもしれませんがそれにしても「CN~DL」までだったり「~DO」までだったり「~DP」までだったりとグラフ範囲がバラバラでグラフを見てもその分左寄りになっていてとってもかっこ悪いものになっています。
この初めの段階で、同じ範囲であれば3日分増えようが2日減ろうが関係なく一括で修正できるのですがスタートの段階で範囲がバラバラなのでせっかく作成したマクロが動きません・・・。
これは、一つ一つ修正するしかないのでしょうか?
マクロ等では、おしりが違う場合一気に揃える技はないでしょうか?
Sub graph_change()
Dim wb As Workbook, ws As Worksheet
Dim str1 As String, str2 As String, i As Integer, j As Integer
str1 = InputBox("変更前の値を入力してください")
If str1 = "" Then Exit Sub
str2 = InputBox("変更後の値を入力してください")
If str2 = "" Then Exit Sub
On Error Resume Next
For Each wb In Workbooks
For Each ws In wb.Worksheets
For j = 1 To ws.ChartObjects.Count
With ws.ChartObjects(j).Chart
For i = 1 To wb.Worksheets.Count
.SeriesCollection.Item(i).Formula = _
Replace(.SeriesCollection.Item(i).Formula, "$" & str1, "$" & str2)
Next i
End With
Next j
Next ws
Next wb
End Sub
グラフの現状と希望(?)です。
上が、現状の状態でマクロ実行後下のグラフになって欲しいです。
19184d353886aee9446cbf2804c7f2.jpeg)
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

回答1件
0
ベストアンサー
こんにちは。
「以前、グラフ範囲を一括で変更」というのは以下を指しているのかと思いました。
違っていれば教えて頂ければと思います。
全シートに対して連続実行する方法について
https://teratail.com/questions/20455
頂いている内容からすると、横軸方向(列)へ日付が配置されているように思えました。
例えば、6行目のデータ最終列は次のような形で求まります。(右方向へ走査して終端を取得)
VBA
1Set rng = Sheet1.Range("D6").End(xlToRight) '仮にD列にデータ先頭があるとして
データに歯抜けが入りうる場合は、たしか一工夫が必要です
私の読み間違えていなければ。という前提の上になってしまいますが
分からない点があります。
恐らくデータの終端(列)が不定になってしまっているのだろうと思いました。
イメージで見ると、11日まである物や8日までしかない物が存在する。
このような状況が
・同シート内でも起こるのか?
・同ブック内のシート毎で異なっているのか?
ほか、シート内で終端(列)が異なった時に
最短の範囲で作るのか(イメージの例なら8日まで)?
最長の範囲で作るのか(イメージの例なら11日まで)?
この辺りの条件が決まっていれば、実現は可能だと思います。
追記 2015/11/19
編集 2015/11/20 コードを修正しました
グラフのデータ範囲をチェックして、適切でないと判断した場合に範囲を修正するサンプルを書きました。
末尾の無効(値の入っていないセル)を除外するだけでなく、不足があれば拡張(範囲を拡大)されるようになっています。拡張が不要であれば拡張をしない形に修正できます。
少し"ごちゃっ"としてしまいましたが、以下のコードで動作確認できています。
「ChartCheckMain」を実行頂ければ、アクティブなシート上に存在する全てのグラフについて処理をします。
** 2015/11/20 11:50頃 修正済みのコードです**
VBA
1'<summary> 2' アクティブなシート上に存在する全グラフをチェックする 3'</summary> 4Sub ChartCheckMain() 5 Dim AtvWbk As Workbook 6 Dim AtvSht As Worksheet 7 Dim ChrtObj As ChartObject 8 Dim ChrtCnt As Integer 9 Dim ChrtIdx As Integer 10 Dim ret As Boolean 11 12 Set AtvWbk = ActiveWorkbook 13 Set AtvSht = AtvWbk.ActiveSheet 14 15 For Each ChrtObj In AtvSht.ChartObjects 16 ret = DataRangeChecker(AtvWbk, ChrtObj) 17 Next ChrtObj 18End Sub 19 20'<summary> 21' グラフのデータ範囲をチェックし、無効な範囲を除去 22'</summary> 23'<param name="WBk">Workbook</param> 24'<param name="ChrtObj">チェック対象のChartObject</param> 25'<returns>関数の成否</returns> 26Function DataRangeChecker(ByRef WBk As Workbook, ByRef ChrtObj As ChartObject) As Boolean 27 On Error Resume Next 28 Err.Clear 29 30 Const ENCLOSE_SYMBOL As String = "'" 31 Const SYMBOL_ESCAPE As String = "''" 32 Const ARGS_PATTERN As String = "\((\(.+\)|[^()]*),(\(.+\)|[^()]*),(.+?),(\d+)\)$" 33 Const RANGE_PATTERN As String = "^('.+'|[^']+)!([^!]+)$" 34 35 Dim Regex 'VBScript.RegExp 36 Dim Matches 'RegExp.Matches 37 Dim SrsCol As SeriesCollection '系列のコレクション 38 Dim SrsCnt As Integer '系列数 39 Dim SrsIdx As Integer '系列のインデックス 40 Dim Srs As Series '系列 41 Dim FormulaValue As String 'Formulaの値 42 Dim SrsName As String '凡例の表示 43 Dim SrsLabels As String '項目軸のラベル 44 Dim SrsValues As String '値(プロット対象のデータ範囲) 45 Dim SrsOrder As String 'オーダー 46 Dim ShtName As String 'データの存在するシート名 47 Dim RngStr As String '範囲を示す文字列 48 Dim Rng As Range 'Range 49 Dim ColEnd As Long 'データ範囲の終端(列) 50 Dim NewRng As Range 'チェックによって決定されたデータ範囲 51 Dim NewSrsLabels As String 'チェックによって決定されたラベル(SERIESの第2引数) 52 Dim NewSrsValues As String 'チェックによって決定された値(SERIESの第3引数) 53 Dim NewColumnCnt As Long 'チェックによって決定されたデータ範囲の大きさ(列数) 54 Dim NewFormula As String 'チェックによって決定されたFormulaの値 55 Dim UseEnclose As Boolean 56 57 DataRangeChecker = False 58 59 Debug.Print "==========================================" 60 61 Set Regex = CreateObject("VBScript.RegExp") 62 If Err.Number <> 0 Then 63 Debug.Print "> VBScript.RegExpが取得できませんでした" 64 Exit Function 65 End If 66 67 Debug.Print "Target Chart : " & ChrtObj.Name 68 69 Set SrsCol = ChrtObj.Chart.SeriesCollection '系列のコレクションを取得 70 SrsCnt = SrsCol.Count 71 Debug.Print "Series.Count : " & CStr(SrsCnt) 72 73 '引数で受け取ったChrtObjが無効であれば関数を抜ける 74 If Err.Number <> 0 Then Exit Function 75 76 '全ての系列についてチェック 77 For SrsIdx = 1 To SrsCnt 78 Set Srs = SrsCol.Item(SrsIdx) 79 FormulaValue = Srs.Formula 80 Debug.Print Chr(10) & "Series[" & CStr(SrsIdx) & "]" 81 Debug.Print " Formula" & FormulaValue 82 83 '文字列から情報を抽出 84 With Regex 85 .Pattern = ARGS_PATTERN 86 .IgnoreCase = False 87 .Global = True 88 Set Matches = .Execute(FormulaValue) 89 End With 90 91 If Matches.Count > 0 Then 92 SrsName = Matches(0).SubMatches.Item(0) '凡例の表示 93 SrsLabels = Matches(0).SubMatches.Item(1) '項目軸のラベル 94 SrsValues = Matches(0).SubMatches.Item(2) '値 95 SrsOrder = Matches(0).SubMatches.Item(3) 'オーダー 96 Else 97 Debug.Print " > 情報の抽出に失敗しました" 98 SrsName = SrsLabels = SrsValues = SrsOrder = "" 99 GoTo CONTINUE_FOR 100 End If 101 102 Debug.Print " Param(0) = " & SrsName 103 Debug.Print " Param(1) = " & SrsLabels 104 Debug.Print " Param(2) = " & SrsValues 105 Debug.Print " Param(3) = " & SrsOrder 106 107 '------------------------------------- 108 'SERIESの第3引数(データ範囲)のチェック 109 '------------------------------------- 110 With Regex 111 .Pattern = RANGE_PATTERN 112 .IgnoreCase = False 113 .Global = True 114 115 Set Matches = .Execute(SrsValues) 116 End With 117 118 If Matches.Count > 0 Then 119 ShtName = Matches(0).SubMatches.Item(0) 'シート名 120 RngStr = Matches(0).SubMatches.Item(1) 'データ範囲 121 122 ShtName = CheckEnclose(ShtName, ENCLOSE_SYMBOL, SYMBOL_ESCAPE, UseEnclose) 123 124 'データ範囲のチェック 125 With WBk.Worksheets.Item(ShtName) 126 Set Rng = .Range(RngStr) 127 Set NewRng = .Range(.Cells(Rng.Row, Rng.Column), .Cells(Rng.Row, Rng.End(xlToRight).Column)) 128 End With 129 NewColumnCnt = NewRng.Columns.Count 130 If UseEnclose = True Then 131 NewSrsValues = ENCLOSE_SYMBOL _ 132 + Replace(ShtName, ENCLOSE_SYMBOL, SYMBOL_ESCAPE) _ 133 + ENCLOSE_SYMBOL _ 134 + "!" + NewRng.Address 135 Else 136 NewSrsValues = ShtName + "!" + NewRng.Address 137 End If 138 139 Else 140 '第3引数に!が存在しなかった 141 NewSrsValues = SrsValues 142 End If 143 144 '現在のデータ範囲とチェックによって決定されたデータ範囲を比較 145 If SrsValues = NewSrsValues Then 146 '一致した場合は次の系列へ 147 Debug.Print " > データ範囲の変更は行われませんでした" 148 GoTo CONTINUE_FOR 149 End If 150 151 '----------------------------------------- 152 'SERIESの第2引数(項目軸のラベル)をチェック 153 '----------------------------------------- 154 With Regex 155 .Pattern = RANGE_PATTERN 156 .IgnoreCase = False 157 .Global = True 158 Set Matches = .Execute(SrsLabels) 159 End With 160 161 If Matches.Count > 0 Then 162 ShtName = Matches(0).SubMatches.Item(0) 'シート名 163 RngStr = Matches(0).SubMatches.Item(1) 'データ範囲 164 165 ShtName = CheckEnclose(ShtName, ENCLOSE_SYMBOL, SYMBOL_ESCAPE, UseEnclose) 166 167 'ラベルの範囲を決定 168 With WBk.Worksheets.Item(ShtName) 169 Set Rng = .Range(RngStr) 170 Set NewRng = .Range(.Cells(Rng.Row, Rng.Column), .Cells(Rng.Row, Rng.Column + NewColumnCnt - 1)) 171 End With 172 If UseEnclose = True Then 173 NewSrsLabels = ENCLOSE_SYMBOL _ 174 + Replace(ShtName, ENCLOSE_SYMBOL, SYMBOL_ESCAPE) _ 175 + ENCLOSE_SYMBOL _ 176 + "!" + NewRng.Address 177 Else 178 NewSrsLabels = ShtName + "!" + NewRng.Address 179 End If 180 181 Else 182 '第2引数に!が存在しなかった 183 NewSrsLabels = SrsLabels 184 End If 185 186 187 '新しくFormulaに設定する文字列を生成 188 NewFormula = "=SERIES(" & SrsName & "," & NewSrsLabels & "," & NewSrsValues & "," & SrsOrder & ")" 189 190 Debug.Print Chr(10) & " [Formula]" 191 Debug.Print " " & FormulaValue 192 Debug.Print " " & NewFormula 193 194 '生成したFormulaの値を系列に適用 195 If Err.Number = 0 Then Srs.Formula = NewFormula 196 197CONTINUE_FOR: 198 199 If Err.Number <> 0 Then GoTo EXIT_FUNCTION 200 201 Next SrsIdx 202 203 204EXIT_FUNCTION: 205 If Err.Number = 0 Then 206 Debug.Print Chr(10) & "> 正常に終了しました" & Chr(10) 207 DataRangeChecker = True 208 End If 209 210 Set Regex = Nothing 211End Function 212 213'<summay> 214' 指定の文字列がsymbolで囲まれているかチェック 215'</summary> 216'<param name="strInput">チェック対象の文字列</param> 217'<param name="symbol">シンボル</param> 218'<param name="escape">エスケープ</param> 219'<param name="UseEnclose">シンボルで囲まれているかを返す</param> 220'<returns>囲っているシンボルを除去した文字列を返す</returns> 221Function CheckEnclose(strInput As String, symbol As String, escape As String, _ 222 ByRef UseEnclose As Boolean) As String 223 Dim result As String 224 225 If Left(strInput, Len(symbol)) = symbol And Right(strInput, Len(symbol)) = symbol Then 226 '文字列がsymbolで囲まれている 227 UseEnclose = True 228 result = Mid(strInput, Len(symbol) + 1, Len(strInput) - Len(symbol) * 2) '前後のシンボルを除去 229 result = Replace(result, escape, symbol) 'エスケープの処理 230 Else 231 '文字列がsymbolで囲まれていない 232 UseEnclose = False 233 result = strInput 234 End If 235 236 CheckEnclose = result 237End Function
・データ範囲内に歯抜けが存在する事を想定していない(あいだに空のセルが入らない)
・プロットする系列のデータは横(列)方向に並んでいる
・末尾(右端)側の適切でない範囲を修正するのみで先頭(左端)側の修正はしない
・データ範囲の指定が連続していて"とびとび(不連続)"の指示を想定していない
・ブックを跨いだデータ範囲の指定が存在しない(回避策はあり)
などの前提になっていますので、この前提で問題があるようでしたら教えてください。
4番目の「連続でない」状況があると結構やっかいになりますが、他はそんなに難易度高くないです。
一応、質問文中で頂いているコードの中から呼び出せるように「引数で指定された単一のグラフについて処理をする」機能として関数化しました。
以下のように書いてあげれば、変更処理の前にデータ範囲の修正ができます。
DataRangeChecker(<グラフの存在するワークブック>, <対象とするグラフ>)
VBA
1Sub graph_change() 2 '省略 3 For j = 1 To ws.ChartObjects.Count 4 5 '正常に処理を完了したか?をTrue/Falseで返すように作りましたが、 6 '戻り値が不要であれば、コメント側のようにCallで呼んでもらっても良いと思います。 7 ret = DataRangeChecker(wb, ws.ChartObjects(j)) ' <-------------------------- 8 'Call DataRangeChecker(wb, ws.ChartObjects(j)) 9 10 With ws.ChartObjects(j).Chart 11 '省略
大量にDebug.Printを入れてますが、確認用です。最終的なコードからは該当行を削除してもらって構いません。
投稿2015/11/18 07:23
編集2015/11/20 03:35総合スコア294
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。