3

I just spent a significant amount of time creating identical graphs in several dozen excel files (all containing identically formatted data,) and believe there has to be a more efficient way of completing what I've just done.

To simplify things, consider 50 excel documents with data in the same format. Does there exist a method of automatically:

  • Creating a simple line graph
  • Adding axis labels, a chart label, removing horizontal grid lines
  • Including a trend line/R^2 value
  • Saving the new workbook to a certain location with "_graphed" appended to the filename

Would this be something that an Excel VBA could be used for?

nitrl
  • 2,185
  • 2
  • 15
  • 15
  • Yep, takes care of points 1-3 and definitely would have saved me time. Ideally, though, I'd be looking for something further automated. For example, the file names of the documents I am working on (e.g. "aviation_accidents.csv" contain the information that I end up passing into the chart axes & title (x: "Date" y: "Normalized search volume for 'aviation accidents'", Title: "Time Series for normalized search volume of "aviation accidents"). It would be nice to have a solution that could essentially take the file name as an input variable and use it when creating the chart. – nitrl Aug 08 '13 at 22:02
  • Very nice, it hadn't occurred to me that I could pull the file name from within the workbook. Works great. – nitrl Aug 10 '13 at 23:24

2 Answers2

1

For this sort of problem I would start by recording a macro of the steps you take manually into a personal macro workbook. You can then look at the code produced by Excel and you may find that you don't need to make too many changes for this to be useful as a generic procedure.

After testing, if you wanted to take the automation one step further you could write a little procedure to loop through all of the Excel files in a directory and call your chart procedure for each file when it is open. I can dig out come code I wrote doing something similar if it will help.

Update Here is a thread where I have provided some code to loop through all of the files containing some given text (in this example ".pdf" but could just as easily be ".xls" to cover xlsx, xlsm etc).

Also this example prints out a list of the files it finds to a worksheet. This is a good start to test the results, but once this is okay you would need to replace the line:

Range(c).Offset(j, 0).Value = vFileList(i)

With some code to open that workbook and call your code to generate the chart. Let me know if you get stuck.

Further Update

I have reviewed the code referred to above and made a few improvements including an additional parameter for you to specify the name of a macro that you want to run against each of the workbooks opened (that meet the condition specified). The macro that you use in the call must exist in the workbook that you are calling all of the other workbooks from (e.g. if the chart macro is in your personal workbook then the code below should also be placed in your personal macro workbook):

Option Explicit

Sub FileLoop(pDirPath As String, _
             Optional pPrintToSheet = False, _
             Optional pStartCellAddr = "$A$1", _
             Optional pCheckCondition = False, _
             Optional pFileNameContains = "xxx", _
             Optional pProcToRunOnWb)

On Error GoTo PrintFileList_err

    ' Local constants / variables
    Const cProcName = "FileLoop"
    Dim vFileList() As String ' array for file names
    Dim i As Integer          ' iterator for file name array
    Dim j As Integer          ' match counter
    Dim c As String
    ' variables for optional param pProcToRunOnWb
    Dim vFullPath As String
    Dim vTmpPath As String
    Dim wb As Workbook

    vFullPath = Application.ThisWorkbook.FullName
    vFileList = GetFileList(pDirPath)
    c = pStartCellAddr
    j = 0

    For i = LBound(vFileList) To UBound(vFileList)
        ' if condition is met (i.e. filename cotains text or condition is not required...
        If pCheckCondition And InStr(1, vFileList(i), pFileNameContains, vbTextCompare) > 0 _
           Or Not pCheckCondition Then

            ' print name to sheet if required...
            If pPrintToSheet Then
                Range(c).Offset(j, 0).Value = vFileList(i)
                j = j + 1 ' increment row offset
            End If

            ' open wb to run macro if required...
            If pProcToRunOnWb <> "" Then
                Application.DisplayAlerts = False ' set alerts off so that macro can run in other wb
                vTmpPath = pDirPath & "\" & vFileList(i)
                Set wb = Workbooks.Open(Filename:=vTmpPath)
                Workbooks(wb.Name).Activate
                Application.Run "'" & vFullPath & "'!" & pProcToRunOnWb
                wb.Close (True) ' save and close workbook
                Application.DisplayAlerts = True ' set alerts back on
            End If

        End If

        Debug.Print vFileList(i)
    Next i

   ' clean up
   Set wb = Nothing

PrintFileList_exit:
    Exit Sub

PrintFileList_err:
    Debug.Print "Error in ", cProcName, vbCrLf, "Err no: ", Err.Number, _
                vbCrLf, "Err Description: ", Err.Description
    Resume Next

End Sub

Function GetFileList(pDirPath As String) As Variant
On Error GoTo GetFileList_err

    ' Local constants / variables
    Const cProcName = "GetFileList"
    Dim objFSO As Object
    Dim objFolder As Object
    Dim objFile As Object
    Dim c As Double           ' upper bound for file name array
    Dim i As Double           ' iterator for file name array
    Dim vFileList() As String ' array for file names

    Set objFSO = CreateObject("Scripting.FileSystemObject")
    Set objFolder = objFSO.GetFolder(pDirPath)
    c = objFolder.Files.Count
    i = 0

    ReDim vFileList(1 To c)  ' set bounds on file array now we know count

    'Loop through the Files collection
    For Each objFile In objFolder.Files
        'Debug.Print objFile.Name
        i = i + 1
        vFileList(i) = objFile.Name
    Next

    'Clean up!
    Set objFolder = Nothing
    Set objFile = Nothing
    Set objFSO = Nothing

    GetFileList = vFileList

GetFileList_exit:
    Exit Function

GetFileList_err:
    Debug.Print "Error in ", cProcName, vbCrLf, "Err no: ", Err.Number, _
                vbCrLf, "Err Description: ", Err.Description
    Resume Next

End Function

You can call this from another macro or from the immediate window (ctrl+G) with the parameters required e.g. to get all files containing '.xls', and run a macro named 'your_macro_name_here' the code would be:

call FileLoop("C:\Users\Prosserc\Dropbox\Docs\Stack_Overflow\Test", False, "", True, ".xls", "your_macro_name_here")

Obviously change the path in the first parameter to point to the directory containing the files that you want to run the macro against.

Community
  • 1
  • 1
ChrisProsser
  • 12,598
  • 6
  • 35
  • 44
  • I was able to use your (and pnuts') suggestions to take care of everything happening within the file, but I think you're right about needing the last step. If it's not too inconvenient, I'd love that bit of code! – nitrl Aug 10 '13 at 23:28
  • @nitrl I have posted an update above. Initially I just included a link to the thread I mentioned, then thought it would be good to have a version of this code with an extra parameter to run a macro against all of the workbooks in the loop, so posted a new version of the code above. Let me know how you get on with this. – ChrisProsser Aug 11 '13 at 12:44
1

There is a library called Xlsxwriter for both python and perl which allows for the automation of chart generation. For some sample python code, see my post here.

Community
  • 1
  • 1
Bryce Guinta
  • 3,456
  • 1
  • 35
  • 36