I often make a lot of scatter plots (column j vs column i) in a single Worksheet. I want to export them as png/jpg files. Each plot would need a sensible file name. I have thought that the file name could be something like plot_[column i]_[column j].png.
How do I get the column (like C or AE) from each plot (or ActiveChart)? Then I can create a file name string to be fed in to the Export method. I am a complete beginner for VBA macros, but understand some Visual Basic.
You can extract that information from the source data string using text functions. The source data is available using .SeriesCollection:
activesheet.chartobjects("Chart 1").chart.SeriesCollection(1).Formula
will return something like this:
"=SERIES(,Sheet1!$A$1:$A$4,Sheet1!$B$1:$B$4,1)"
That contains the two columns you need, "A" and "B". You can extract them using text functions like INSTR(), MID(), and LEFT(). Here is an example using debug.print to output the columns. I'm assuming you already know how to export them since that was not included in your question.
Sub FindSourceColumns()
Dim sourcedata, firstcolumn, secondcolumn As String, c as chartobject
for each c in activesheet.chartobjects
sourcedata = c.Chart.SeriesCollection(1).Formula
firstcolumn = Mid(sourcedata, InStr(sourcedata, "!$") + 2, 5)
firstcolumn = Left(firstcolumn, InStr(firstcolumn, "$") - 1)
Debug.Print firstcolumn
secondcolumn = Mid(sourcedata, InStr(InStr(sourcedata, "!$") + 2, sourcedata, "!$") + 2, 5)
secondcolumn = Left(secondcolumn, InStr(secondcolumn, "$") - 1)
Debug.Print secondcolumn
next c
End Sub
Related
I have an excel file with the following links:
These links are connected to files with the following data:
I want the yellow part of the notepad file to be read into the .xlsx file yellow parts (the notepad is an opened version of the .tbl file). The dotted parts differ for each Version number. (This code is used as a check that the right discount curve is used). However, the discount_curve.tbl format is the only format the next programme used is able to handle. Therefore, it has the same name just in a different folder.
Is there a way excel/vba can read in every third line whilst the file read in depends on the folder link? I strongly prefer to have the whole process automated since there are many many version numbers. Furthermore, I do not want to change the file formatting, since I want the process to be as clean as possible.
Could someone help me out?
Kind regards.
Please, try the next function, if the necessary data to be extracted exists in a single file, at every three rows.. It will return a 2D array able to be dropped at once in the range you need:
Function extractThirdLine(filePath As String) As Variant
Dim arrTxt, i As Long, arrFin, k As Long
'read the file content in an array:
arrTxt = Split(CreateObject("Scripting.FileSystemObject").OpenTextFile(filePath, 1).ReadAll, vbCrLf)
ReDim arrFin(1 To Int(UBound(arrTxt) / 3) + 1, 1 To 1)
For i = 2 To UBound(arrTxt) Step 3 'start from 2, because arrTxt is 1D array
k = k + 1
arrFin(k, 1) = arrTxt(i) 'build the filal array containing the necessary rows
Next i
extractThirdLine = arrFin
End Function
Your picture does not show the rows and columns headers. So, supposing that the range you show us exists in columns "A:C" and you need to place the extracted data in column "D:D", please use the next way:
Sub testExtractThirdLine()
Dim filePath As String, arrVal, el
filePath = "your text file full name" 'please write here the correct file name
arrVal = extractThirdLine(filePath)
Range("D1").Resize(UBound(arrVal), 1).value = arrVal
End Sub
If the range you show is not the one I supposed, you cam easily adapt Range("D1") to the immediately after the columns range and its row to be the first row of the range in discussion.
If something not clear enough, please do not hesitate to ask for clarifications.
Edited:
But if each third line can be found in a file, for each row, and the path to the respective file is obtained by concatenation of the three columns, the next function will do the job:
Function extractLine(filePath As String) As String
extractLine = Split(CreateObject("Scripting.FileSystemObject").OpenTextFile(filePath, 1).ReadAll, vbCrLf)(2)
End Function
It can be called as:
Sub extractStrings()
Dim i As Long, arr, arrFin, lastRow As Long
lastRow = Range("A" & rows.count).End(xlUp).Row 'supposing that 'C:\' exists in A:A column
arr = Range("A2:C" & lastRow).value
ReDim arrFin(1 To UBound(arr), 1 To 1)
For i = 1 To UBound(arr)
arrFin(i, 1) = extractLine(arr(i, 1) & arr(i, 2) & arr(i, 3))
Next i
'drop the processed array content at once:
Range("D2").Resize(UBound(arrFin), 1).value = arrFin
End Sub
Seems like you're looking for common I/O opearations i.e. reading file line by line.
Pretty good example was shown [here][1]
To reach your goal we need to add some if-conditions to extract every third line of your text files.
Modulo division will be a good helper.
For example we have 'i' as row number
then we just need to make an if condition looks smth like that:
If (i mod 3) = 0 Then ...
It means that we're looking for every 'i' which divided by 3 gives us a remainder of 0
This way our code will look something like this
Sub ReadFileLineByLine()
Dim my_file As Integer
Dim text_line As String
Dim file_name As String
Dim i As Integer
file_name = "C:\text_file.txt"
my_file = FreeFile()
Open file_name For Input As my_file
i = 1
While Not EOF(my_file)
Line Input #my_file, text_line
If (i mod 3) = 0 Then
Cells(i, "A").Value = text_line
End If
i = i + 1
Wend
End Sub
[1]: https://excel.officetuts.net/vba/read-a-text-file/#:~:text=Reading%20a%20file%20line%20by%20line,-Let's%20read%20text&text=Open%20VBA%20Edit%20(Alt%20%2B%20F11,and%20insert%20the%20following%20code.&text=First%2C%20a%20new%20file%20is,places%20it%20inside%20a%20worksheet.
You can create a User function that will read the lines from the given file and return the third one.
Here is such a function (Disclaimer: there is no error management in this code it can probably be improved a lot)
Function Get3rdLine(filename As String)
Dim f As Long
f = FreeFile
Open filename For Input As f
Line Input #f, Get3rdLine ' just ignore this line
Line Input #f, Get3rdLine ' and this one too
Line Input #f, Get3rdLine ' and return this one
Close #f
End Function
You can call it with the path of the file you want to read from:
=Get3rdLine(CONCATENATE(A1,B1,C1)) for example if your path is defined by cells A1, B1 and C1.
I am looking for a way to extract text between 2 characters and copy them to a column at the end of the spreadsheet.
For example, my text looks like [abcdefg], all in Column A, I am looking to extract the text between the "[" and copy it to a new column at the end of the worksheet (as a new column)
Thanks
I would resort to functions since they're just the easiest. To pull the data between 2 characters, you'd use a mixture of MID and FIND functions.
So, assuming your data was in cell A1, you could put this formula in the cell where you want the parsed value:
=MID(A1,FIND("[",A1)+1,FIND("]",A1)-FIND("[",A1)-1)
If you wanted to automate it, you could put it into a macro then copy / paste-special values to remove the function and keep the values.
This is for text in Cell 1, 1 but you can toss some variables in there as you loop through your rows. It will grab the values within square brackets & trim it, additional text can be in front or behind the brackets.
Dim iPos1 As Integer
Dim iPos2 As Integer
iPos1 = InStr(Sheet1.Cells(1, 1), "[")
iPos2 = InStr(Sheet1.Cells(1, 1), "]")
Sheet1.Cells(1, 2) = Trim(Mid(Sheet1.Cells(1, 1), iPos1 + 1, iPos2 - iPos1 - 1))
If you want to write this into a vba module, looping through all entries in the A column and extracting the text inside the [] into an entry in column B, it might look something like:
Dim ws as Worksheet
Dim i as integer
Dim lastRow as Integer
Dim brack1pos as Integer
Dim brack2pos as Integer
Set ws = ThisWorkbook.Worksheets("My Sheet Name")
for i = 1 to lastRow 'I'll leave to you how to find the last row
brack1pos = InStr(ws.Range("A" & i), "[")
brack2pos = InStr(ws.Range("A" & i), "]")
ws.Range("B" & i) = Trim(Mid(ws.Range("A" & i), brack1pos + 1, brack2pos - brack1pos - 1))
next
I want to rotate values from a separate Excel file like this:
To a vertical list:
I mean, after every ninth value, I want the program to start a new column (as in the picture).
I manage to do this manually (ofc B) ) when the different "sheets" are on the same document (Sheet1, Sheet2 etc).
Is this even possible what I am trying, without too much further programming? Should I be using Excel macros? I appreciate all the help I get..!
Store the data matrix in an array and slice off transposed 'rows' of values.
Dim x As Long, vVALs As Variant
With Worksheets("Sheet1")
vVALs = .Range("A2:I5").Value2
For x = LBound(vVALs, 1) To UBound(vVALs, 1)
.Cells(7, 1).Offset((x - 1) * UBound(vVALs, 2)).Resize(UBound(vVALs, 2), 1) = _
Application.Transpose(Application.Index(vVALs, x, 0))
Next x
End With
I have an issue of assigning several columns to a variable in Visual Basic. Is this possible at all?
Currently my code looks like this:
Do
Dim data As String
data = wsh.Cells(Row, 2) 'Data for barcodes is taken from this column
Now my question is: how can I assign/store more columns to a data variable? The method i tried below isn't permitted:
data= wsh.Cells(Row,2), wshCells(Row, 3), wshCells(Row, 4)
Basically, what I want to do is to take several columns that have some integer values. Out of these values, I want to generate QR Code and populate some specific columns with the generated QR code. With the current method that I have, I can only select one single column and populate another column. I can't select multiple columns and populate multiple columns respectively.
This is one the QR code is inserted into a specific column.
Set qrcode_cell = wsh.Cells(Row, 1) 'The cell where the QR Code will be placed
*Note i am using an excel add on tool called StrokeScribe.
Your help and suggestions are appreciated.
Transform your data variable into a list
dim datas() as string, pos as integer
pos = -1
' Add a column to datas
public sub addColumn(byval row as integer, byval col as integer)
pos = pos + 1
redim preserve datas(pos)
datas(pos) = wsh.Cells(row, col)
end sub
' Convert your datas into the format of your qrcode
public function retrieveData() as string
retrieveData = ""
dim data as string
for each data in datas
' data is the string you had in wsh.Cells(Row, col)
' do what you want with this column
next
' affect the result to "retrieveData" to retrieve datas in the needed format
end function
Just append each cell value to the existing string using &:
Do
Dim data As String
data = wsh.Cells(Row,2) & wsh.Cells(Row, 3) & wsh.Cells(Row, 4)
If you mean you want to add a value each time you loop then something like:
Do
Dim data As String
data = data & wsh.Cells(Row,2), wshCells(Row, 3), wshCells(Row, 4)
So you're just appending the cells onto the existing string.
I want to have labels next to data points in an Excel chart. There is a VBA code from Microsoft for this purpose:
http://support2.microsoft.com/kb/914813/en-us
Sub AttachLabelsToPoints()
'Dimension variables.
Dim Counter As Integer, ChartName As String, xVals As String
' Disable screen updating while the subroutine is run.
Application.ScreenUpdating = False
'Store the formula for the first series in "xVals".
xVals = ActiveChart.SeriesCollection(1).Formula
'Extract the range for the data from xVals.
xVals = Mid(xVals, InStr(InStr(xVals, ","), xVals, _
Mid(Left(xVals, InStr(xVals, "!") - 1), 9)))
xVals = Left(xVals, InStr(InStr(xVals, "!"), xVals, ",") - 1)
Do While Left(xVals, 1) = ","
xVals = Mid(xVals, 2)
Loop
'Attach a label to each data point in the chart.
For Counter = 1 To Range(xVals).Cells.Count
ActiveChart.SeriesCollection(1).Points(Counter).HasDataLabel = _
True
ActiveChart.SeriesCollection(1).Points(Counter).DataLabel.Text = _
Range(xVals).Cells(Counter, 1).Offset(0, -1).Value
Next Counter
End Sub
It works so far. But only if the collection has no name:
When I name the collection then the macro returns an error:
Does anyone know how to use the code provided by Mircosoft and still be able to name the data collection?
Excel 2013 introduced the capability to label a chart series with data from cells, after many years of users begging for it. Select the series, and add data labels. Select the data labels and format them. Under Label Options in the task pane, look for Label Contains, select the Value From Cells option, and select the range containing the label text.
And even before this, you could use a free add-in called the XY Chart Labeler (which works on all charts that support data labels, not just XY charts), which you can download from Applications Professionals. It's written by Rob Bovey, a former Microsoft Excel MVP.
I had the same problem. All you need to do is replace the hardcoded '9' with 'InStr(xVals, ",")' and it will accept any length SERIES name in the field before the first comma.
There already are some good answers like ZAT's one, explaining how to add labels to a data point in native Excel with VBA language.
But if you don't know anything about VBA it might be difficult to understand. For complex charts like this one I prefer to use Javascript which I think is more "readable" than VBA. And if you want to make a dynamic and interactive chart, javascript comes with a lot of powerful libraries.
Here is a working code I have written for you, with plotly.js (the documentation is very good for js beginners) :
https://www.funfun.io/1/#/edit/5a60bbe7404f66229bda3e39
So to build this chart I put my data in the embedded spreadsheet, which I can then use in my javascript code thanks to a Json file.
I can create a scatter plot like so :
var trace1 = {
x: firstX,
y: firstY,
text: firstLabel,
mode: 'markers+text',
textposition:'top right'
};
The firstX and firstY variable are the X and Y values.
To add a label to each point I added a label to text and changed the mode to marker+textinstead of just marker.
Once you've made your chart you can load it in Excel by passing the URL in an Excel add-in called Funfun.
Here is how it looks like:
Disclosure : I’m a developer of funfun
Try this after chart generation (assuming chart in the same sheet):
(modify this according to your need)
Option Explicit
Sub RenameChartDataLabel()
Dim rngDLabel As Range
Dim iii as integer, pp as integer, dlcount as integer
Set rngDLabel = ActiveSheet.Range("A2:A6") 'change range for datalabels text
ActiveSheet.ChartObjects("Chart 2").Activate 'change chart name
dlcount = ActiveChart.SeriesCollection(1).DataLabels.Count
iii = 1
pp = 1
For iii = dlcount To 1 Step -1
ActiveChart.SeriesCollection(1).DataLabels(iii).Select
Selection.Text = rngDLabel(pp).Value
Selection.Font.Bold = True
Selection.Position = xlLabelPositionAbove
pp = pp + 1
Next
Set rngDLabel = Nothing
End Sub