问:
VBA - Trying to add a range between two strings as a series to a graph
I'm trying to write a macro which will add a large number of datapoints as a new series to a chart in excel.

I currently import voltammogram data from a csv file to the spreadsheet into two columns (Potential and Current). This data is made of 43 cycles containing between 500 and 1500 values each (I have no control over how many points the software spits out, which complicates things).

I would like to scan the data for a string which appears at the start of each cycle "Potential*" and at the end of each cycle "PN", add these values to the chart and then move on to the next cycle.

I've combined a few different solutions from different searches to get a messy solution that works sometimes but not always; I'm fairly confident it would work if each cycle contained the same number of points but that's unfortunately not the case.

My messy solution:

```<code>Sub InsertChart()

Dim first As Long, last As Long
first = 4
last = Range(Range("A:A").Find("*Potential*").Offset(1), Range("A:A").Find("*PN*", Range("A:A").Find("*Potential*")).Offset(-1, 1)).Cells.Count

Dim wsChart As Worksheet
Set wsChart = Sheets(1)

wsChart.Activate
wsChart.Shapes.AddChart.Select

Dim chart As chart
Set chart = ActiveChart
chart.ChartType = xlXYScatter
    ActiveChart.ClearToMatchStyle
    ActiveChart.ChartStyle = 240
    ActiveChart.Axes(xlCategory).MinimumScale = 0
    ActiveChart.Axes(xlCategory).MaximumScale = 1.5
    ActiveChart.Axes(xlCategory).MajorUnit = 0.1

' adding series
chart.SeriesCollection.NewSeries
chart.SeriesCollection(1).Name = "Cycle 01"
chart.SeriesCollection(1).XValues = "=" & ActiveSheet.Name & "!$A$" & first & ":$A$" & last
chart.SeriesCollection(1).Values = "=" & ActiveSheet.Name & "!$B$" & first & ":$B$" & last

chart.SeriesCollection.NewSeries
chart.SeriesCollection(2).Name = "Cycle 02"
chart.SeriesCollection(2).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 2) + 4 & ":$A$" & last * 3
chart.SeriesCollection(2).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 2) + 4 & ":$B$" & last * 3

chart.SeriesCollection.NewSeries
chart.SeriesCollection(3).Name = "Cycle 03"
chart.SeriesCollection(3).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 3) + 4 & ":$A$" & last * 4
chart.SeriesCollection(3).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 3) + 4 & ":$B$" & last * 4

chart.SeriesCollection.NewSeries
chart.SeriesCollection(4).Name = "Cycle 04"
chart.SeriesCollection(4).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 4) + 4 & ":$A$" & last * 5
chart.SeriesCollection(4).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 4) + 4 & ":$B$" & last * 5

chart.SeriesCollection.NewSeries
chart.SeriesCollection(5).Name = "Cycle 05"
chart.SeriesCollection(5).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 5) + 4 & ":$A$" & last * 6
chart.SeriesCollection(5).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 5) + 4 & ":$B$" & last * 6

chart.SeriesCollection.NewSeries
chart.SeriesCollection(6).Name = "Cycle 06"
chart.SeriesCollection(6).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 6) + 4 & ":$A$" & last * 7
chart.SeriesCollection(6).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 6) + 4 & ":$B$" & last * 7

chart.SeriesCollection.NewSeries
chart.SeriesCollection(7).Name = "Cycle 07"
chart.SeriesCollection(7).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 7) + 4 & ":$A$" & last * 8
chart.SeriesCollection(7).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 7) + 4 & ":$B$" & last * 8

chart.SeriesCollection.NewSeries
chart.SeriesCollection(8).Name = "Cycle 08"
chart.SeriesCollection(8).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 8) + 4 & ":$A$" & last * 9
chart.SeriesCollection(8).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 8) + 4 & ":$B$" & last * 9

chart.SeriesCollection.NewSeries
chart.SeriesCollection(9).Name = "Cycle 09"
chart.SeriesCollection(9).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 9) + 4 & ":$A$" & last * 10
chart.SeriesCollection(9).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 9) + 4 & ":$B$" & last * 10

chart.SeriesCollection.NewSeries
chart.SeriesCollection(10).Name = "Cycle 10"
chart.SeriesCollection(10).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 10) + 4 & ":$A$" & last * 11
chart.SeriesCollection(10).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 10) + 4 & ":$B$" & last * 11

chart.SeriesCollection.NewSeries
chart.SeriesCollection(11).Name = "Cycle 11"
chart.SeriesCollection(11).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 11) + 4 & ":$A$" & last * 12
chart.SeriesCollection(11).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 11) + 4 & ":$B$" & last * 12

chart.SeriesCollection.NewSeries
chart.SeriesCollection(12).Name = "Cycle 12"
chart.SeriesCollection(12).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 12) + 4 & ":$A$" & last * 13
chart.SeriesCollection(12).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 12) + 4 & ":$B$" & last * 13

chart.SeriesCollection.NewSeries
chart.SeriesCollection(13).Name = "Cycle 13"
chart.SeriesCollection(13).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 13) + 4 & ":$A$" & last * 14
chart.SeriesCollection(13).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 13) + 4 & ":$B$" & last * 14

chart.SeriesCollection.NewSeries
chart.SeriesCollection(14).Name = "Cycle 14"
chart.SeriesCollection(14).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 14) + 4 & ":$A$" & last * 15
chart.SeriesCollection(14).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 14) + 4 & ":$B$" & last * 15

chart.SeriesCollection.NewSeries
chart.SeriesCollection(15).Name = "Cycle 15"
chart.SeriesCollection(15).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 15) + 4 & ":$A$" & last * 16
chart.SeriesCollection(15).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 15) + 4 & ":$B$" & last * 16

chart.SeriesCollection.NewSeries
chart.SeriesCollection(16).Name = "Cycle 16"
chart.SeriesCollection(16).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 16) + 4 & ":$A$" & last * 17
chart.SeriesCollection(16).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 16) + 4 & ":$B$" & last * 17

chart.SeriesCollection.NewSeries
chart.SeriesCollection(17).Name = "Cycle 17"
chart.SeriesCollection(17).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 17) + 4 & ":$A$" & last * 18
chart.SeriesCollection(17).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 17) + 4 & ":$B$" & last * 18

chart.SeriesCollection.NewSeries
chart.SeriesCollection(18).Name = "Cycle 18"
chart.SeriesCollection(18).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 18) + 4 & ":$A$" & last * 19
chart.SeriesCollection(18).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 18) + 4 & ":$B$" & last * 19

chart.SeriesCollection.NewSeries
chart.SeriesCollection(19).Name = "Cycle 19"
chart.SeriesCollection(19).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 19) + 4 & ":$A$" & last * 20
chart.SeriesCollection(19).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 19) + 4 & ":$B$" & last * 20

chart.SeriesCollection.NewSeries
chart.SeriesCollection(20).Name = "Cycle 20"
chart.SeriesCollection(20).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 20) + 4 & ":$A$" & last * 21
chart.SeriesCollection(20).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 20) + 4 & ":$B$" & last * 21

chart.SeriesCollection.NewSeries
chart.SeriesCollection(21).Name = "Cycle 21"
chart.SeriesCollection(21).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 21) + 4 & ":$A$" & last * 22
chart.SeriesCollection(21).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 21) + 4 & ":$B$" & last * 22

chart.SeriesCollection.NewSeries
chart.SeriesCollection(22).Name = "Cycle 22"
chart.SeriesCollection(22).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 22) + 4 & ":$A$" & last * 23
chart.SeriesCollection(22).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 22) + 4 & ":$B$" & last * 23

chart.SeriesCollection.NewSeries
chart.SeriesCollection(23).Name = "Cycle 23"
chart.SeriesCollection(23).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 23) + 4 & ":$A$" & last * 24
chart.SeriesCollection(23).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 23) + 4 & ":$B$" & last * 24

chart.SeriesCollection.NewSeries
chart.SeriesCollection(21).Name = "Cycle 24"
chart.SeriesCollection(21).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 24) + 4 & ":$A$" & last * 25
chart.SeriesCollection(21).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 24) + 4 & ":$B$" & last * 25

chart.SeriesCollection.NewSeries
chart.SeriesCollection(25).Name = "Cycle 25"
chart.SeriesCollection(25).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 25) + 4 & ":$A$" & last * 26
chart.SeriesCollection(25).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 25) + 4 & ":$B$" & last * 26

chart.SeriesCollection.NewSeries
chart.SeriesCollection(26).Name = "Cycle 26"
chart.SeriesCollection(26).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 26) + 4 & ":$A$" & last * 27
chart.SeriesCollection(26).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 26) + 4 & ":$B$" & last * 27

chart.SeriesCollection.NewSeries
chart.SeriesCollection(27).Name = "Cycle 27"
chart.SeriesCollection(27).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 27) + 4 & ":$A$" & last * 28
chart.SeriesCollection(27).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 27) + 4 & ":$B$" & last * 28

chart.SeriesCollection.NewSeries
chart.SeriesCollection(28).Name = "Cycle 28"
chart.SeriesCollection(28).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 28) + 4 & ":$A$" & last * 29
chart.SeriesCollection(28).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 28) + 4 & ":$B$" & last * 29

chart.SeriesCollection.NewSeries
chart.SeriesCollection(29).Name = "Cycle 29"
chart.SeriesCollection(29).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 29) + 4 & ":$A$" & last * 30
chart.SeriesCollection(29).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 29) + 4 & ":$B$" & last * 30

chart.SeriesCollection.NewSeries
chart.SeriesCollection(30).Name = "Cycle 30"
chart.SeriesCollection(30).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 30) + 4 & ":$A$" & last * 31
chart.SeriesCollection(30).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 30) + 4 & ":$B$" & last * 31

chart.SeriesCollection.NewSeries
chart.SeriesCollection(31).Name = "Cycle 31"
chart.SeriesCollection(31).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 31) + 4 & ":$A$" & last * 32
chart.SeriesCollection(31).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 31) + 4 & ":$B$" & last * 32

chart.SeriesCollection.NewSeries
chart.SeriesCollection(32).Name = "Cycle 32"
chart.SeriesCollection(32).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 32) + 4 & ":$A$" & last * 33
chart.SeriesCollection(32).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 32) + 4 & ":$B$" & last * 33

chart.SeriesCollection.NewSeries
chart.SeriesCollection(33).Name = "Cycle 33"
chart.SeriesCollection(33).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 33) + 4 & ":$A$" & last * 34
chart.SeriesCollection(33).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 33) + 4 & ":$B$" & last * 34

chart.SeriesCollection.NewSeries
chart.SeriesCollection(34).Name = "Cycle 34"
chart.SeriesCollection(34).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 34) + 4 & ":$A$" & last * 35
chart.SeriesCollection(34).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 34) + 4 & ":$B$" & last * 35

chart.SeriesCollection.NewSeries
chart.SeriesCollection(35).Name = "Cycle 35"
chart.SeriesCollection(35).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 35) + 4 & ":$A$" & last * 36
chart.SeriesCollection(35).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 35) + 4 & ":$B$" & last * 36

chart.SeriesCollection.NewSeries
chart.SeriesCollection(36).Name = "Cycle 36"
chart.SeriesCollection(36).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 36) + 4 & ":$A$" & last * 37
chart.SeriesCollection(36).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 36) + 4 & ":$B$" & last * 37

chart.SeriesCollection.NewSeries
chart.SeriesCollection(37).Name = "Cycle 37"
chart.SeriesCollection(37).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 37) + 4 & ":$A$" & last * 38
chart.SeriesCollection(37).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 37) + 4 & ":$B$" & last * 38

chart.SeriesCollection.NewSeries
chart.SeriesCollection(38).Name = "Cycle 38"
chart.SeriesCollection(38).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 38) + 4 & ":$A$" & last * 39
chart.SeriesCollection(38).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 38) + 4 & ":$B$" & last * 39

chart.SeriesCollection.NewSeries
chart.SeriesCollection(39).Name = "Cycle 39"
chart.SeriesCollection(39).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 39) + 4 & ":$A$" & last * 40
chart.SeriesCollection(39).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 39) + 4 & ":$B$" & last * 40

chart.SeriesCollection.NewSeries
chart.SeriesCollection(40).Name = "Cycle 40"
chart.SeriesCollection(40).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 40) + 4 & ":$A$" & last * 41
chart.SeriesCollection(40).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 40) + 4 & ":$B$" & last * 41

chart.SeriesCollection.NewSeries
chart.SeriesCollection(41).Name = "Cycle 41"
chart.SeriesCollection(41).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 41) + 4 & ":$A$" & last * 42
chart.SeriesCollection(41).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 41) + 4 & ":$B$" & last * 42

chart.SeriesCollection.NewSeries
chart.SeriesCollection(42).Name = "Cycle 42"
chart.SeriesCollection(42).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 42) + 4 & ":$A$" & last * 43
chart.SeriesCollection(42).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 42) + 4 & ":$B$" & last * 43

chart.SeriesCollection.NewSeries
chart.SeriesCollection(43).Name = "Cycle 43"
chart.SeriesCollection(43).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 43) + 4 & ":$A$" & last * 44
chart.SeriesCollection(43).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 43) + 4 & ":$B$" & last * 44
End Sub
</code>```

Any help or pointers in the right direction would be great.

After using your help, I've updated the macro to use your code and it's almost there. It's only the Y values (Current) that get output as 0s but I feel like that may be my fault during tweaking the code to make it work with the data.

```<code>'Plots the Excel Data
Sub Voltammogram()

'Add Chart
Dim wsChart As Worksheet
Set wsChart = Sheets(1)

wsChart.Activate
wsChart.Shapes.AddChart.Select

Dim chart As chart
    Set chart = ActiveChart
Dim chartsize As Range
    Set chartsize = ActiveSheet.Range("D1:o20")
Dim Chart_obj As ChartObject
    Set Chart_obj = ActiveSheet.ChartObjects(1)

chart.ChartType = xlXYScatter
chart.HasTitle = True
chart.ChartTitle.Text = ActiveSheet.Name
chart.Axes(xlCategory, xlPrimary).HasTitle = True
ActiveChart.Axes(xlCategory).AxisTitle.Text = "Potential (V)"
chart.Axes(xlValue, xlPrimary).HasTitle = True
ActiveChart.Axes(xlValue).AxisTitle.Text = "Current (uA)"
ActiveChart.Axes(xlCategory).MinimumScale = 0
ActiveChart.Axes(xlCategory).MaximumScale = 1.5
ActiveChart.Axes(xlCategory).MajorUnit = 0.1
ActiveChart.ChartStyle = 240
Chart_obj.Height = chartsize.Height
Chart_obj.Width = chartsize.Width
Chart_obj.Top = chartsize.Top
Chart_obj.Left = chartsize.Left
ActiveChart.ChartArea.ClearContents

'Find Last Row
    Dim LastRow As Long
    With ActiveSheet
        LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
    End With
    Cells(LastRow + 2, 1).Value = "PN"
    Cells(LastRow + 4, 1).Value = "END"

'End of Data Flag
Dim End_of_data As Boolean
End_of_data = False

'Chart Object
'Dim Chart_obj As ChartObject
Set Chart_obj = ActiveSheet.ChartObjects(1)

'Series Variable
Dim MySeries As Series
Dim Series_Col As SeriesCollection
Set Series_Col = Chart_obj.chart.SeriesCollection

'Range Offset Variable
Dim i As Integer
i = 3

'Series Index Value
Dim si As Integer
si = 1

'Value Variables
Dim Voltage, Current As String

'Value Collections
Dim Vol_List As New Collection
Dim Cur_List As New Collection

'Looping through the Sheet collecting Cycle data
While (End_of_data = False)

    Voltage = ActiveSheet.Range("A1").Offset(i, 0).Value
    Current = ActiveSheet.Range("A1").Offset(i, 1).Value

    'Checking for a Cycle End
    If (Voltage = "PN") Then
        'Incrementing the series index at the end of cycle
        si = si + 1

        'Creating the Series with all of the cycle data
        Set MySeries = Series_Col.NewSeries
        MySeries.Values = Collection_To_Array(Cur_List)
        MySeries.XValues = Collection_To_Array(Vol_List)
        MySeries.Name = "Cycle " & (si - 1)

        'Clearing out the List
         Set Vol_List = New Collection
         Set Cur_List = New Collection

    'Checking for end of data. This assumes there are no blanks in your data collection. You may need to update this logic
    ElseIf (Voltage = "END") Then

        'Exiting the Loop
        End_of_data = True
    Else

        'Adding the Data to the List
        If (Voltage <> "Potential" And Voltage <> "PN") Then
            Vol_List.Add (Voltage)
            Cur_List.Add (Current)
        End If
    End If

    'Incrementing the offset Counter
    i = i + 1
Wend

End Sub

Function Collection_To_Array(c As Collection) As Variant()
    Length = c.Count - 1
    Dim A() As Variant
    ReDim A(Length)
    Dim i As Integer
    For i = 1 To Length + 1
        A(i - 1) = c.Item(i)        'Arrays are zero based and collections are 1 based
    Next
    Collection_To_Array = A
End Function
</code>```

Edit: Turns out the problem of Y values appearing as 0 was caused by me forgetting to switch Dim Voltage, Current to Dim Current, Voltage. The new problem is that values are being recorded and are visible in "view data" on the graph but aren't being plotted, there's also an overflow error after 21 cycles (around 30000 datapoints). I think the invisible plots are caused by empty cells which I should be able to fix but I can't find the source of the overflow.

```<code>'Plots the Excel Data
Sub Voltammogram()

'Add Chart
Dim chart As chart
Dim chartsize As Range
Dim Chart_obj As ChartObject
Dim VolMin As Double
    VolMin = WorksheetFunction.Min(Range("A:A"))
Dim VolMax As Double
    VolMax = WorksheetFunction.Max(Range("A:A"))

ActiveSheet.Shapes.AddChart.Select
    Set chart = ActiveChart
    Set chartsize = ActiveSheet.Range("D1:O20")
    Set Chart_obj = ActiveSheet.ChartObjects(1)
    chart.ChartType = xlXYScatter
    chart.HasTitle = True
    chart.ChartTitle.Text = ActiveSheet.Name
    chart.Axes(xlCategory, xlPrimary).HasTitle = True
    ActiveChart.Axes(xlCategory).AxisTitle.Text = "Potential (V)"
    chart.Axes(xlValue, xlPrimary).HasTitle = True
    ActiveChart.Axes(xlValue).AxisTitle.Text = "Current (uA)"
    ActiveChart.Axes(xlCategory).MinimumScale = VolMin
    ActiveChart.Axes(xlCategory).MaximumScale = VolMax
    ActiveChart.Axes(xlCategory).MajorUnit = 0.1
    ActiveChart.ChartStyle = 240
    ActiveChart.Axes(xlCategory).TickLabelPosition = xlLow
    Chart_obj.Height = chartsize.Height
    Chart_obj.Width = chartsize.Width
    Chart_obj.Top = chartsize.Top
    Chart_obj.Left = chartsize.Left
    ActiveChart.ChartArea.ClearContents

'Find Last Row
    Dim LastRow As Long
    With ActiveSheet
        LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
    End With
    If Not (Cells(LastRow, 1) = "END") Then
        Cells(LastRow + 2, 1).Value = "PN"
        Cells(LastRow + 4, 1).Value = "END"
    End If

'End of Data Flag
Dim End_of_data As Boolean
End_of_data = False

'Chart Object
'Dim Chart_obj As ChartObject
'Set Chart_obj = ActiveSheet.ChartObjects(1)

'Series Variable
Dim MySeries As Series
Dim Series_Col As SeriesCollection
Set Series_Col = Chart_obj.chart.SeriesCollection

'Range Offset Variable
Dim i As Integer
i = 2

'Series Index Value
Dim si As Integer
si = 1

'Value Variables
Dim Current, Voltage As String

'Value Collections
Dim Vol_List As New Collection
Dim Cur_List As New Collection

'Looping through the Sheet collecting Cycle data
While (End_of_data = False)

    Voltage = ActiveSheet.Range("A1").Offset(i, 0).Value
    Current = ActiveSheet.Range("A1").Offset(i, 1).Value

    'Checking for a Cycle End
    If (Voltage = "PN") Then
        'Incrementing the series index at the end of cycle
        si = si + 1

        'Creating the Series with all of the cycle data
        Set MySeries = Series_Col.NewSeries
        MySeries.Values = Collection_To_Array(Cur_List)
        MySeries.XValues = Collection_To_Array(Vol_List)
        MySeries.Name = "Cycle " & (si - 1)

        'Clearing out the List
         Set Vol_List = New Collection
         Set Cur_List = New Collection

    'Checking for end of data. This assumes there are no blanks in your data collection. You may need to update this logic
    ElseIf (Voltage = "END") Then

        'Exiting the Loop
        End_of_data = True
    Else

        'Adding the Data to the List
        If (Voltage <> "Potential" And Voltage <> "PN") Then
            Vol_List.Add (Voltage)
            Cur_List.Add (Current)
        End If
    End If

    'Incrementing the offset Counter
    i = i + 1
Wend

End Sub

Function Collection_To_Array(c As Collection) As Variant()
    c.Remove (1)
    c.Remove (c.Count)
    Length = c.Count - 1
    Dim a() As Variant
    ReDim a(Length)
    Dim i As Integer
    For i = 1 To Length + 1
        a(i - 1) = c.Item(i)        'Arrays are zero based and collections are 1 based
    Next
    Collection_To_Array = a

End Function
</code>```

答:
```<code>    'Plots the Excel Data
Sub Plot_data()

'End of Data Flag
Dim End_of_data As Boolean
End_of_data = False

'Chart Object
Dim Chart_obj As ChartObject
Set Chart_obj = Sheet6.ChartObjects(1)

'Series Variable
Dim MySeries As Series
Dim Series_Col As SeriesCollection
Set Series_Col = Chart_obj.Chart.SeriesCollection

'Range Offset Variable
Dim i As Integer
i = 0

'Series Index Value
Dim si As Integer
si = 1

'Value Variables
Dim Voltage, Current As String

'Value Collections
Dim Vol_List As New Collection
Dim Cur_List As New Collection

'Looping through the Sheet collecting Cycle data
While (End_of_data = False)

    Voltage = Sheet6.Range("A1").Offset(i, 0).value
    Current = Sheet6.Range("A1").Offset(i, 1).value

    'Checking for a Cycle End
    If (Voltage = "PN") Then
        'Incrementing the series index at the end of cycle
        si = si + 1

        'Creating the Series with all of the cycle data
        Set MySeries = Series_Col.NewSeries
        MySeries.Values = Sheet2.Collection_To_Array(Vol_List)
        MySeries.XValues = Sheet2.Collection_To_Array(Cur_List)

        'Clearing out the List
         Set Vol_List = New Collection
         Set Cur_List = New Collection

    'Checking for end of data. This assumes there are no blanks in your data collection. You may need to update this logic
    ElseIf (Voltage = "") Then

        'Exiting the Loop
        End_of_data = True
    Else

        'Adding the Data to the List
        If (Voltage <> "Potential" And Voltage <> "PN") Then
            Vol_List.Add (Voltage)
            Cur_List.Add (Current)
        End If
    End If

    'Incrementing the offset Counter
    i = i + 1
Wend

End Sub

Function Collection_To_Array(c As Collection) As Variant()
    Length = c.Count - 1
    Dim A() As Variant
    ReDim A(Length)
    Dim i As Integer
    For i = 1 To Length + 1
        A(i - 1) = c.Item(i)        'Arrays are zero based and collections are 1 based
    Next
    Collection_To_Array = A
End Function
</code>```

Body:
I'm trying to write a macro which will add a large number of datapoints as a new series to a chart in excel.

I currently import voltammogram data from a csv file to the spreadsheet into two columns (Potential and Current). This data is made of 43 cycles containing between 500 and 1500 values each (I have no control over how many points the software spits out, which complicates things).

I would like to scan the data for a string which appears at the start of each cycle "Potential*" and at the end of each cycle "PN", add these values to the chart and then move on to the next cycle.

I've combined a few different solutions from different searches to get a messy solution that works sometimes but not always; I'm fairly confident it would work if each cycle contained the same number of points but that's unfortunately not the case.

My messy solution:

Sub InsertChart()

Dim first As Long, last As Long
first = 4
last = Range(Range("A:A").Find("*Potential*").Offset(1), Range("A:A").Find("*PN*", Range("A:A").Find("*Potential*")).Offset(-1, 1)).Cells.Count

Dim wsChart As Worksheet
Set wsChart = Sheets(1)

wsChart.Activate
wsChart.Shapes.AddChart.Select

Dim chart As chart
Set chart = ActiveChart
chart.ChartType = xlXYScatter
    ActiveChart.ClearToMatchStyle
    ActiveChart.ChartStyle = 240
    ActiveChart.Axes(xlCategory).MinimumScale = 0
    ActiveChart.Axes(xlCategory).MaximumScale = 1.5
    ActiveChart.Axes(xlCategory).MajorUnit = 0.1

' adding series
chart.SeriesCollection.NewSeries
chart.SeriesCollection(1).Name = "Cycle 01"
chart.SeriesCollection(1).XValues = "=" & ActiveSheet.Name & "!$A$" & first & ":$A$" & last
chart.SeriesCollection(1).Values = "=" & ActiveSheet.Name & "!$B$" & first & ":$B$" & last

chart.SeriesCollection.NewSeries
chart.SeriesCollection(2).Name = "Cycle 02"
chart.SeriesCollection(2).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 2) + 4 & ":$A$" & last * 3
chart.SeriesCollection(2).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 2) + 4 & ":$B$" & last * 3

chart.SeriesCollection.NewSeries
chart.SeriesCollection(3).Name = "Cycle 03"
chart.SeriesCollection(3).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 3) + 4 & ":$A$" & last * 4
chart.SeriesCollection(3).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 3) + 4 & ":$B$" & last * 4

chart.SeriesCollection.NewSeries
chart.SeriesCollection(4).Name = "Cycle 04"
chart.SeriesCollection(4).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 4) + 4 & ":$A$" & last * 5
chart.SeriesCollection(4).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 4) + 4 & ":$B$" & last * 5

chart.SeriesCollection.NewSeries
chart.SeriesCollection(5).Name = "Cycle 05"
chart.SeriesCollection(5).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 5) + 4 & ":$A$" & last * 6
chart.SeriesCollection(5).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 5) + 4 & ":$B$" & last * 6

chart.SeriesCollection.NewSeries
chart.SeriesCollection(6).Name = "Cycle 06"
chart.SeriesCollection(6).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 6) + 4 & ":$A$" & last * 7
chart.SeriesCollection(6).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 6) + 4 & ":$B$" & last * 7

chart.SeriesCollection.NewSeries
chart.SeriesCollection(7).Name = "Cycle 07"
chart.SeriesCollection(7).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 7) + 4 & ":$A$" & last * 8
chart.SeriesCollection(7).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 7) + 4 & ":$B$" & last * 8

chart.SeriesCollection.NewSeries
chart.SeriesCollection(8).Name = "Cycle 08"
chart.SeriesCollection(8).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 8) + 4 & ":$A$" & last * 9
chart.SeriesCollection(8).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 8) + 4 & ":$B$" & last * 9

chart.SeriesCollection.NewSeries
chart.SeriesCollection(9).Name = "Cycle 09"
chart.SeriesCollection(9).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 9) + 4 & ":$A$" & last * 10
chart.SeriesCollection(9).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 9) + 4 & ":$B$" & last * 10

chart.SeriesCollection.NewSeries
chart.SeriesCollection(10).Name = "Cycle 10"
chart.SeriesCollection(10).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 10) + 4 & ":$A$" & last * 11
chart.SeriesCollection(10).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 10) + 4 & ":$B$" & last * 11

chart.SeriesCollection.NewSeries
chart.SeriesCollection(11).Name = "Cycle 11"
chart.SeriesCollection(11).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 11) + 4 & ":$A$" & last * 12
chart.SeriesCollection(11).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 11) + 4 & ":$B$" & last * 12

chart.SeriesCollection.NewSeries
chart.SeriesCollection(12).Name = "Cycle 12"
chart.SeriesCollection(12).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 12) + 4 & ":$A$" & last * 13
chart.SeriesCollection(12).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 12) + 4 & ":$B$" & last * 13

chart.SeriesCollection.NewSeries
chart.SeriesCollection(13).Name = "Cycle 13"
chart.SeriesCollection(13).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 13) + 4 & ":$A$" & last * 14
chart.SeriesCollection(13).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 13) + 4 & ":$B$" & last * 14

chart.SeriesCollection.NewSeries
chart.SeriesCollection(14).Name = "Cycle 14"
chart.SeriesCollection(14).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 14) + 4 & ":$A$" & last * 15
chart.SeriesCollection(14).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 14) + 4 & ":$B$" & last * 15

chart.SeriesCollection.NewSeries
chart.SeriesCollection(15).Name = "Cycle 15"
chart.SeriesCollection(15).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 15) + 4 & ":$A$" & last * 16
chart.SeriesCollection(15).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 15) + 4 & ":$B$" & last * 16

chart.SeriesCollection.NewSeries
chart.SeriesCollection(16).Name = "Cycle 16"
chart.SeriesCollection(16).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 16) + 4 & ":$A$" & last * 17
chart.SeriesCollection(16).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 16) + 4 & ":$B$" & last * 17

chart.SeriesCollection.NewSeries
chart.SeriesCollection(17).Name = "Cycle 17"
chart.SeriesCollection(17).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 17) + 4 & ":$A$" & last * 18
chart.SeriesCollection(17).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 17) + 4 & ":$B$" & last * 18

chart.SeriesCollection.NewSeries
chart.SeriesCollection(18).Name = "Cycle 18"
chart.SeriesCollection(18).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 18) + 4 & ":$A$" & last * 19
chart.SeriesCollection(18).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 18) + 4 & ":$B$" & last * 19

chart.SeriesCollection.NewSeries
chart.SeriesCollection(19).Name = "Cycle 19"
chart.SeriesCollection(19).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 19) + 4 & ":$A$" & last * 20
chart.SeriesCollection(19).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 19) + 4 & ":$B$" & last * 20

chart.SeriesCollection.NewSeries
chart.SeriesCollection(20).Name = "Cycle 20"
chart.SeriesCollection(20).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 20) + 4 & ":$A$" & last * 21
chart.SeriesCollection(20).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 20) + 4 & ":$B$" & last * 21

chart.SeriesCollection.NewSeries
chart.SeriesCollection(21).Name = "Cycle 21"
chart.SeriesCollection(21).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 21) + 4 & ":$A$" & last * 22
chart.SeriesCollection(21).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 21) + 4 & ":$B$" & last * 22

chart.SeriesCollection.NewSeries
chart.SeriesCollection(22).Name = "Cycle 22"
chart.SeriesCollection(22).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 22) + 4 & ":$A$" & last * 23
chart.SeriesCollection(22).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 22) + 4 & ":$B$" & last * 23

chart.SeriesCollection.NewSeries
chart.SeriesCollection(23).Name = "Cycle 23"
chart.SeriesCollection(23).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 23) + 4 & ":$A$" & last * 24
chart.SeriesCollection(23).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 23) + 4 & ":$B$" & last * 24

chart.SeriesCollection.NewSeries
chart.SeriesCollection(21).Name = "Cycle 24"
chart.SeriesCollection(21).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 24) + 4 & ":$A$" & last * 25
chart.SeriesCollection(21).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 24) + 4 & ":$B$" & last * 25

chart.SeriesCollection.NewSeries
chart.SeriesCollection(25).Name = "Cycle 25"
chart.SeriesCollection(25).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 25) + 4 & ":$A$" & last * 26
chart.SeriesCollection(25).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 25) + 4 & ":$B$" & last * 26

chart.SeriesCollection.NewSeries
chart.SeriesCollection(26).Name = "Cycle 26"
chart.SeriesCollection(26).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 26) + 4 & ":$A$" & last * 27
chart.SeriesCollection(26).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 26) + 4 & ":$B$" & last * 27

chart.SeriesCollection.NewSeries
chart.SeriesCollection(27).Name = "Cycle 27"
chart.SeriesCollection(27).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 27) + 4 & ":$A$" & last * 28
chart.SeriesCollection(27).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 27) + 4 & ":$B$" & last * 28

chart.SeriesCollection.NewSeries
chart.SeriesCollection(28).Name = "Cycle 28"
chart.SeriesCollection(28).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 28) + 4 & ":$A$" & last * 29
chart.SeriesCollection(28).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 28) + 4 & ":$B$" & last * 29

chart.SeriesCollection.NewSeries
chart.SeriesCollection(29).Name = "Cycle 29"
chart.SeriesCollection(29).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 29) + 4 & ":$A$" & last * 30
chart.SeriesCollection(29).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 29) + 4 & ":$B$" & last * 30

chart.SeriesCollection.NewSeries
chart.SeriesCollection(30).Name = "Cycle 30"
chart.SeriesCollection(30).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 30) + 4 & ":$A$" & last * 31
chart.SeriesCollection(30).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 30) + 4 & ":$B$" & last * 31

chart.SeriesCollection.NewSeries
chart.SeriesCollection(31).Name = "Cycle 31"
chart.SeriesCollection(31).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 31) + 4 & ":$A$" & last * 32
chart.SeriesCollection(31).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 31) + 4 & ":$B$" & last * 32

chart.SeriesCollection.NewSeries
chart.SeriesCollection(32).Name = "Cycle 32"
chart.SeriesCollection(32).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 32) + 4 & ":$A$" & last * 33
chart.SeriesCollection(32).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 32) + 4 & ":$B$" & last * 33

chart.SeriesCollection.NewSeries
chart.SeriesCollection(33).Name = "Cycle 33"
chart.SeriesCollection(33).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 33) + 4 & ":$A$" & last * 34
chart.SeriesCollection(33).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 33) + 4 & ":$B$" & last * 34

chart.SeriesCollection.NewSeries
chart.SeriesCollection(34).Name = "Cycle 34"
chart.SeriesCollection(34).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 34) + 4 & ":$A$" & last * 35
chart.SeriesCollection(34).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 34) + 4 & ":$B$" & last * 35

chart.SeriesCollection.NewSeries
chart.SeriesCollection(35).Name = "Cycle 35"
chart.SeriesCollection(35).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 35) + 4 & ":$A$" & last * 36
chart.SeriesCollection(35).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 35) + 4 & ":$B$" & last * 36

chart.SeriesCollection.NewSeries
chart.SeriesCollection(36).Name = "Cycle 36"
chart.SeriesCollection(36).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 36) + 4 & ":$A$" & last * 37
chart.SeriesCollection(36).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 36) + 4 & ":$B$" & last * 37

chart.SeriesCollection.NewSeries
chart.SeriesCollection(37).Name = "Cycle 37"
chart.SeriesCollection(37).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 37) + 4 & ":$A$" & last * 38
chart.SeriesCollection(37).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 37) + 4 & ":$B$" & last * 38

chart.SeriesCollection.NewSeries
chart.SeriesCollection(38).Name = "Cycle 38"
chart.SeriesCollection(38).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 38) + 4 & ":$A$" & last * 39
chart.SeriesCollection(38).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 38) + 4 & ":$B$" & last * 39

chart.SeriesCollection.NewSeries
chart.SeriesCollection(39).Name = "Cycle 39"
chart.SeriesCollection(39).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 39) + 4 & ":$A$" & last * 40
chart.SeriesCollection(39).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 39) + 4 & ":$B$" & last * 40

chart.SeriesCollection.NewSeries
chart.SeriesCollection(40).Name = "Cycle 40"
chart.SeriesCollection(40).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 40) + 4 & ":$A$" & last * 41
chart.SeriesCollection(40).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 40) + 4 & ":$B$" & last * 41

chart.SeriesCollection.NewSeries
chart.SeriesCollection(41).Name = "Cycle 41"
chart.SeriesCollection(41).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 41) + 4 & ":$A$" & last * 42
chart.SeriesCollection(41).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 41) + 4 & ":$B$" & last * 42

chart.SeriesCollection.NewSeries
chart.SeriesCollection(42).Name = "Cycle 42"
chart.SeriesCollection(42).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 42) + 4 & ":$A$" & last * 43
chart.SeriesCollection(42).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 42) + 4 & ":$B$" & last * 43

chart.SeriesCollection.NewSeries
chart.SeriesCollection(43).Name = "Cycle 43"
chart.SeriesCollection(43).XValues = "=" & ActiveSheet.Name & "!$A$" & (last * 43) + 4 & ":$A$" & last * 44
chart.SeriesCollection(43).Values = "=" & ActiveSheet.Name & "!$B$" & (last * 43) + 4 & ":$B$" & last * 44
End Sub

Any help or pointers in the right direction would be great.

After using your help, I've updated the macro to use your code and it's almost there. It's only the Y values (Current) that get output as 0s but I feel like that may be my fault during tweaking the code to make it work with the data.

'Plots the Excel Data
Sub Voltammogram()

'Add Chart
Dim wsChart As Worksheet
Set wsChart = Sheets(1)

wsChart.Activate
wsChart.Shapes.AddChart.Select

Dim chart As chart
    Set chart = ActiveChart
Dim chartsize As Range
    Set chartsize = ActiveSheet.Range("D1:o20")
Dim Chart_obj As ChartObject
    Set Chart_obj = ActiveSheet.ChartObjects(1)

chart.ChartType = xlXYScatter
chart.HasTitle = True
chart.ChartTitle.Text = ActiveSheet.Name
chart.Axes(xlCategory, xlPrimary).HasTitle = True
ActiveChart.Axes(xlCategory).AxisTitle.Text = "Potential (V)"
chart.Axes(xlValue, xlPrimary).HasTitle = True
ActiveChart.Axes(xlValue).AxisTitle.Text = "Current (uA)"
ActiveChart.Axes(xlCategory).MinimumScale = 0
ActiveChart.Axes(xlCategory).MaximumScale = 1.5
ActiveChart.Axes(xlCategory).MajorUnit = 0.1
ActiveChart.ChartStyle = 240
Chart_obj.Height = chartsize.Height
Chart_obj.Width = chartsize.Width
Chart_obj.Top = chartsize.Top
Chart_obj.Left = chartsize.Left
ActiveChart.ChartArea.ClearContents

'Find Last Row
    Dim LastRow As Long
    With ActiveSheet
        LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
    End With
    Cells(LastRow + 2, 1).Value = "PN"
    Cells(LastRow + 4, 1).Value = "END"

'End of Data Flag
Dim End_of_data As Boolean
End_of_data = False

'Chart Object
'Dim Chart_obj As ChartObject
Set Chart_obj = ActiveSheet.ChartObjects(1)

'Series Variable
Dim MySeries As Series
Dim Series_Col As SeriesCollection
Set Series_Col = Chart_obj.chart.SeriesCollection

'Range Offset Variable
Dim i As Integer
i = 3

'Series Index Value
Dim si As Integer
si = 1

'Value Variables
Dim Voltage, Current As String

'Value Collections
Dim Vol_List As New Collection
Dim Cur_List As New Collection

'Looping through the Sheet collecting Cycle data
While (End_of_data = False)

    Voltage = ActiveSheet.Range("A1").Offset(i, 0).Value
    Current = ActiveSheet.Range("A1").Offset(i, 1).Value

    'Checking for a Cycle End
    If (Voltage = "PN") Then
        'Incrementing the series index at the end of cycle
        si = si + 1

        'Creating the Series with all of the cycle data
        Set MySeries = Series_Col.NewSeries
        MySeries.Values = Collection_To_Array(Cur_List)
        MySeries.XValues = Collection_To_Array(Vol_List)
        MySeries.Name = "Cycle " & (si - 1)

        'Clearing out the List
         Set Vol_List = New Collection
         Set Cur_List = New Collection

    'Checking for end of data. This assumes there are no blanks in your data collection. You may need to update this logic
    ElseIf (Voltage = "END") Then

        'Exiting the Loop
        End_of_data = True
    Else

        'Adding the Data to the List
        If (Voltage <> "Potential" And Voltage <> "PN") Then
            Vol_List.Add (Voltage)
            Cur_List.Add (Current)
        End If
    End If

    'Incrementing the offset Counter
    i = i + 1
Wend

End Sub

Function Collection_To_Array(c As Collection) As Variant()
    Length = c.Count - 1
    Dim A() As Variant
    ReDim A(Length)
    Dim i As Integer
    For i = 1 To Length + 1
        A(i - 1) = c.Item(i)        'Arrays are zero based and collections are 1 based
    Next
    Collection_To_Array = A
End Function

Edit: Turns out the problem of Y values appearing as 0 was caused by me forgetting to switch Dim Voltage, Current to Dim Current, Voltage. The new problem is that values are being recorded and are visible in "view data" on the graph but aren't being plotted, there's also an overflow error after 21 cycles (around 30000 datapoints). I think the invisible plots are caused by empty cells which I should be able to fix but I can't find the source of the overflow.

'Plots the Excel Data
Sub Voltammogram()

'Add Chart
Dim chart As chart
Dim chartsize As Range
Dim Chart_obj As ChartObject
Dim VolMin As Double
    VolMin = WorksheetFunction.Min(Range("A:A"))
Dim VolMax As Double
    VolMax = WorksheetFunction.Max(Range("A:A"))

ActiveSheet.Shapes.AddChart.Select
    Set chart = ActiveChart
    Set chartsize = ActiveSheet.Range("D1:O20")
    Set Chart_obj = ActiveSheet.ChartObjects(1)
    chart.ChartType = xlXYScatter
    chart.HasTitle = True
    chart.ChartTitle.Text = ActiveSheet.Name
    chart.Axes(xlCategory, xlPrimary).HasTitle = True
    ActiveChart.Axes(xlCategory).AxisTitle.Text = "Potential (V)"
    chart.Axes(xlValue, xlPrimary).HasTitle = True
    ActiveChart.Axes(xlValue).AxisTitle.Text = "Current (uA)"
    ActiveChart.Axes(xlCategory).MinimumScale = VolMin
    ActiveChart.Axes(xlCategory).MaximumScale = VolMax
    ActiveChart.Axes(xlCategory).MajorUnit = 0.1
    ActiveChart.ChartStyle = 240
    ActiveChart.Axes(xlCategory).TickLabelPosition = xlLow
    Chart_obj.Height = chartsize.Height
    Chart_obj.Width = chartsize.Width
    Chart_obj.Top = chartsize.Top
    Chart_obj.Left = chartsize.Left
    ActiveChart.ChartArea.ClearContents

'Find Last Row
    Dim LastRow As Long
    With ActiveSheet
        LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
    End With
    If Not (Cells(LastRow, 1) = "END") Then
        Cells(LastRow + 2, 1).Value = "PN"
        Cells(LastRow + 4, 1).Value = "END"
    End If

'End of Data Flag
Dim End_of_data As Boolean
End_of_data = False

'Chart Object
'Dim Chart_obj As ChartObject
'Set Chart_obj = ActiveSheet.ChartObjects(1)

'Series Variable
Dim MySeries As Series
Dim Series_Col As SeriesCollection
Set Series_Col = Chart_obj.chart.SeriesCollection

'Range Offset Variable
Dim i As Integer
i = 2

'Series Index Value
Dim si As Integer
si = 1

'Value Variables
Dim Current, Voltage As String

'Value Collections
Dim Vol_List As New Collection
Dim Cur_List As New Collection

'Looping through the Sheet collecting Cycle data
While (End_of_data = False)

    Voltage = ActiveSheet.Range("A1").Offset(i, 0).Value
    Current = ActiveSheet.Range("A1").Offset(i, 1).Value

    'Checking for a Cycle End
    If (Voltage = "PN") Then
        'Incrementing the series index at the end of cycle
        si = si + 1

        'Creating the Series with all of the cycle data
        Set MySeries = Series_Col.NewSeries
        MySeries.Values = Collection_To_Array(Cur_List)
        MySeries.XValues = Collection_To_Array(Vol_List)
        MySeries.Name = "Cycle " & (si - 1)

        'Clearing out the List
         Set Vol_List = New Collection
         Set Cur_List = New Collection

    'Checking for end of data. This assumes there are no blanks in your data collection. You may need to update this logic
    ElseIf (Voltage = "END") Then

        'Exiting the Loop
        End_of_data = True
    Else

        'Adding the Data to the List
        If (Voltage <> "Potential" And Voltage <> "PN") Then
            Vol_List.Add (Voltage)
            Cur_List.Add (Current)
        End If
    End If

    'Incrementing the offset Counter
    i = i + 1
Wend

End Sub

Function Collection_To_Array(c As Collection) As Variant()
    c.Remove (1)
    c.Remove (c.Count)
    Length = c.Count - 1
    Dim a() As Variant
    ReDim a(Length)
    Dim i As Integer
    For i = 1 To Length + 1
        a(i - 1) = c.Item(i)        'Arrays are zero based and collections are 1 based
    Next
    Collection_To_Array = a

End Function


来源: stackexchange

问:
Eclipse C Build selected files generates no executable
I'd like to build a single C file on Windows using Eclipse Helios and Cygwin. I rightclick on the file, select "Build selected file", the console output returns but I can't find an executable. I can't use the build project function because I have multiple folders with different applications. (for example it complains that I have more than one main function)

Console output:

Rebuilding selected file(s)

**** Internal Builder is used for build               **** gcc -O0 -g3 -Wall -c -fmessage-length=0 -ofolder\test.o ..\folder\test.c

Build of selected resources is complete.

Build and Run works when I have just one src folder with a single Hello World file for example.

答:
When you're rebuilding a specific file you're only rebuilding the corresponding object file. There's nothing strange about this.

From gcc manual page:

When you invoke GCC , it normally does preprocessing, compilation, assembly and linking. The "overall options" allow you to stop this process at an intermediate stage. For example, the -c option says not to run the linker. Then the output consists of object files output by the assembler.

ContentLicense: CC BY-SA 3.0


问:
php: loop through json array
I have a json array:

```<code>[
    {
        "var1": "9",
        "var2": "16",
        "var3": "16"
    },
    {
        "var1": "8",
        "var2": "15",
        "var3": "15"
    }
]
</code>```

How can I loop through this array using php?

答:
First you have to decode your json :

```<code>$array = json_decode($the_json_code);
</code>```

Then after the json decoded you have to do the foreach

```<code>foreach ($array as $key => $jsons) { // This will search in the 2 jsons
     foreach($jsons as $key => $value) {
         echo $value; // This will show jsut the value f each key like "var1" will print 9
                       // And then goes print 16,16,8 ...
    }
}
</code>```

If you want something specific just ask for a key like this. Put this between the last foreach.

```<code>if($key == 'var1'){
 echo $value;
}
</code>```

ContentLicense: CC BY-SA 2.5

Title: php: loop through json array

Body:
I have a json array:

[
    {
        "var1": "9",
        "var2": "16",
        "var3": "16"
    },
    {
        "var1": "8",
        "var2": "15",
        "var3": "15"
    }
]

How can I loop through this array using php?

Body:
First you have to decode your json :

$array = json_decode($the_json_code);

Then after the json decoded you have to do the foreach

foreach ($array as $key => $jsons) { // This will search in the 2 jsons
     foreach($jsons as $key => $value) {
         echo $value; // This will show jsut the value f each key like "var1" will print 9
                       // And then goes print 16,16,8 ...
    }
}

If you want something specific just ask for a key like this. Put this between the last foreach.

if($key == 'var1'){
 echo $value;
}


问:
Observable refresh only first time
I have a observable property  (named properties) in my object. Unfortunately, it refreshes  only when I change it first time.

What can be wrong?

Code:

```<code>var Session = function(vm, session) {
var self = this;
ko.mapping.fromJS(session, {}, self);

self.selectedSessionProperty = ko.observable('');

self.restarting = ko.observable(false);

if (! ko.isObservable(self.properties)) {
  self.properties = ko.observableArray();
}

self.availableNewProperties = ko.computed(function() {
  var addedIndex = {};
  $.each(self.properties(), function(index, property) {
    addedIndex[property.key] = true;
  });
  var result = $.grep(vm.availableSessionProperties(), function(property) {
    return ! addedIndex[property.name];
  });
  return result;
});
};
</code>```

答:
try self.properties.valueHasMutated(); after your loop, this should trigger knockout to update.

You can also use the knockout utility functions to help you with arrays: http://www.knockmeout.net/2011/04/utility-functions-in-knockoutjs.html

Title: Observable refresh only first time

Body:
I have a observable property  (named properties) in my object. Unfortunately, it refreshes  only when I change it first time.

What can be wrong?

Code:

var Session = function(vm, session) {
var self = this;
ko.mapping.fromJS(session, {}, self);

self.selectedSessionProperty = ko.observable('');

self.restarting = ko.observable(false);

if (! ko.isObservable(self.properties)) {
  self.properties = ko.observableArray();
}

self.availableNewProperties = ko.computed(function() {
  var addedIndex = {};
  $.each(self.properties(), function(index, property) {
    addedIndex[property.key] = true;
  });
  var result = $.grep(vm.availableSessionProperties(), function(property) {
    return ! addedIndex[property.name];
  });
  return result;
});
};


问:
Spring Cloud config authentication with AWS Code Commit
I'm novice to use spring cloud config server, so is first time for me and i hope i can receive help, thanks in advance for this.
What i can try to do is to configure Spring cloud Configuration Server as central server for configurations among all Microservices.
We are using AWS CodeCommit as SCM repository.
The problem is that i receive always the same error once i try to inve an existing file on AWS CC.
I suppose is a problem of authentication, but i'm not sure
Error screenshot
This is the bootstrap configuration on Spring CSC

```<code>server.port=9090
management.security.enabled=false
logging.level.org.springframework.web: TRACE
spring.application.name=config-service
spring.cloud.config.server.git.uri: https://git-codecommit.eu-west-1.amazonaws.com/v1/repos/ServiceLayer
</code>```

This is the file in my SCM repository that i'm trying to call:

```<code>configuration:
  projectName: ms-login
server:
  port: 8000
message:
  greeting: Hello from the configuration
</code>```

I've make a several try:

Placed the AWS GIT Credential (NOT the AWS Secret key) in bootstrap properties, but without result. Example:

spring.cloud.config.server.git.username: sergio.greco-at-682088819034
spring.cloud.config.server.git.password: xxxxxxx

Placed the AWS Secret Key \ Identity ID as java parameter once start, as follow:

-Daws.accessKeyId=xxxxxxxxYNOA -Daws.secretKey=xxxxxxxxxxxxxxxx

Set environment variables AWS_ACCESS_KEY_ID \ AWS_SECRET_ACCESS_KEY.

Can someone help me?

答:
You need has the AWS SDK in the classpath.
Relevant documentation on this: http://cloud.spring.io/spring-cloud-static/spring-cloud-config/1.3.1.RELEASE/

Search for “Authentication with AWS CodeCommit”.

Note: The aws-java-sdk-core jar is an optional dependency. If the aws-java-sdk-core jar is not on your classpath, then the AWS Code Commit credential provider will not be created regardless of the git server URI.

Body:
I'm novice to use spring cloud config server, so is first time for me and i hope i can receive help, thanks in advance for this.
What i can try to do is to configure Spring cloud Configuration Server as central server for configurations among all Microservices.
We are using AWS CodeCommit as SCM repository.
The problem is that i receive always the same error once i try to inve an existing file on AWS CC.
I suppose is a problem of authentication, but i'm not sure
Error screenshot
This is the bootstrap configuration on Spring CSC

server.port=9090
management.security.enabled=false
logging.level.org.springframework.web: TRACE
spring.application.name=config-service
spring.cloud.config.server.git.uri: https://git-codecommit.eu-west-1.amazonaws.com/v1/repos/ServiceLayer

This is the file in my SCM repository that i'm trying to call:

configuration:
  projectName: ms-login
server:
  port: 8000
message:
  greeting: Hello from the configuration

I've make a several try:

Placed the AWS GIT Credential (NOT the AWS Secret key) in bootstrap properties, but without result. Example:

spring.cloud.config.server.git.username: sergio.greco-at-682088819034
spring.cloud.config.server.git.password: xxxxxxx

Placed the AWS Secret Key \ Identity ID as java parameter once start, as follow:

-Daws.accessKeyId=xxxxxxxxYNOA -Daws.secretKey=xxxxxxxxxxxxxxxx

Set environment variables AWS_ACCESS_KEY_ID \ AWS_SECRET_ACCESS_KEY.

Can someone help me?


问:
Get minX, maxX, minY, maxY from multidimensional array
I have an array like this

```<code>var my_array = [
  [3,9],
  [1,5],
  [7,2],
  [5,4]
 ]
</code>```

As you can see my_array is a multidimensional array that includes in this case 4 different arrays.

All of the arrays are x/y-coordinates ([3,9] ---> X: 3, Y: 9) and I'd like to move the arrays of the array with ...

the biggest X value,

the biggest Y value,

the smallest X value,

the smallest Y value

... to an object like this:

```<code>var my_object = {
  "minX": [1,5],
  "maxX": [7,2],
  "minY": [7,2],
  "maxY": [3,9]
}
</code>```

The function I've created you can find below, but my function is just returning the listed values from above instead of returning the full array. So my current (wrong) result looks like this:

```<code>var wrong_object = {
  "minX": 1, // missing 5
  "maxX": 7, // missing 2
  "minY": 2, // missing 7
  "maxY": 9  // missing 3
}
</code>```

var my_array = [
  [3, 9],
  [1, 5],
  [7, 2],
  [5, 4]
]

var extreme_result = {}
extreme_result.minX = Math.min.apply(Math, my_array.map(function(i) {
  return i[0]
}));
extreme_result.maxX = Math.max.apply(Math, my_array.map(function(i) {
  return i[0]
}));
extreme_result.minY = Math.min.apply(Math, my_array.map(function(i) {
  return i[1]
}));
extreme_result.maxY = Math.max.apply(Math, my_array.map(function(i) {
  return i[1]
}));

console.log(extreme_result)```

I hope somebody can help me with this problem.

Thanks in advance, Greetings Pete

答:
I would accomplish this by comparing in a forEach rather than mapping, sorting or whatever.

let my_array = [
  [3, 9],
  [1, 5],
  [7, 2],
  [5, 4]
]

let extreme_result = {
  minX: my_array[0],
  minY: my_array[0],
  maxX: my_array[0],
  maxY: my_array[0]
};

my_array.forEach( (el) => {

  if ( extreme_result.minX[0] > el[0] ) {
    extreme_result.minX = el;
  } else if ( extreme_result.maxX[0] < el[0] ) {
    extreme_result.maxX = el;
  }

  if ( extreme_result.minY[1] > el[1] ) {
    extreme_result.minY = el;
  } else if ( extreme_result.maxY[1] < el[1] ) {
    extreme_result.maxY = el;
  }

});

console.info(extreme_result);```

Body:
I have an array like this

var my_array = [
  [3,9],
  [1,5],
  [7,2],
  [5,4]
 ]

As you can see my_array is a multidimensional array that includes in this case 4 different arrays.

All of the arrays are x/y-coordinates ([3,9] ---> X: 3, Y: 9) and I'd like to move the arrays of the array with ...

the biggest X value,

the biggest Y value,

the smallest X value,

the smallest Y value

... to an object like this:

var my_object = {
  "minX": [1,5],
  "maxX": [7,2],
  "minY": [7,2],
  "maxY": [3,9]
}

The function I've created you can find below, but my function is just returning the listed values from above instead of returning the full array. So my current (wrong) result looks like this:

var wrong_object = {
  "minX": 1, // missing 5
  "maxX": 7, // missing 2
  "minY": 2, // missing 7
  "maxY": 9  // missing 3
}

var my_array = [
  [3, 9],
  [1, 5],
  [7, 2],
  [5, 4]
]

var extreme_result = {}
extreme_result.minX = Math.min.apply(Math, my_array.map(function(i) {
  return i[0]
}));
extreme_result.maxX = Math.max.apply(Math, my_array.map(function(i) {
  return i[0]
}));
extreme_result.minY = Math.min.apply(Math, my_array.map(function(i) {
  return i[1]
}));
extreme_result.maxY = Math.max.apply(Math, my_array.map(function(i) {
  return i[1]
}));

console.log(extreme_result)

I hope somebody can help me with this problem.

Thanks in advance, Greetings Pete


问:
Remove stop words from data frame
My data is already in a data frame, with one token per line. I'd like to filter out the rows that contain stop words.

The dataframe looks like:

```<code>docID <- c(1,2,2)
token <- c('the', 'cat', 'sat')
count <- c(10,20,30)
df <- data.frame(docID, token, count)
</code>```

I've tried the below, but get an error:

```<code>library(tidyverse)
library(tidytext)
library(topicmodels)
library(stringr)
data('stop_words')
clean_df <- df %>%
  anti_join(stop_words, by=df$token)
</code>```

Error:

```<code>Error: `by` can't contain join column `the`, `cat`, `sat` which is missing from LHS
</code>```

How can I resolve this?

答:
When you set up anti_join(), you need to say what the column names are, on the left and right hand sides. In the stop_words data object in tidytext, the column is called word and in your dataframe, it is called token.

library(tidyverse)
library(tidytext)

docID <- c(1, 2, 2, 2, 3)
token <- c("the", "cat", "sat", "on-the-mat", "with3hats")
count <- c(10, 20, 30, 10, 20)
df <- data_frame(docID, token, count)

clean_df <- df %>%
  anti_join(stop_words, by= c("token" = "word"))

clean_df
#> # A tibble: 4 x 3
#>   docID token      count
#>   <dbl> <chr>      <dbl>
#> 1  2.00 cat         20.0
#> 2  2.00 sat         30.0
#> 3  2.00 on-the-mat  10.0
#> 4  3.00 with3hats   20.0
```

<p>Notice that "the" is now gone because it is in the <code>stop_words</code> dataset.</p>

<p>In a comment, you asked about removing tokens that contain punctuation or numbers. I'd use <code>filter()</code> for this (you can actually use <code>filter()</code> to remove stopwords too, if you prefer.)

<br/></p>

<pre class="lang-r prettyprint-override"><code>clean_df <- df %>%
  filter(!str_detect(token, "[:punct:]|[:digit:]"))

clean_df
#> # A tibble: 3 x 3
#>   docID token count
#>   <dbl> <chr> <dbl>
#> 1  1.00 the    10.0
#> 2  2.00 cat    20.0
#> 3  2.00 sat    30.0
</code>```

If you want to do both, build up your object with both lines using pipes.

Title: Remove stop words from data frame

Body:
My data is already in a data frame, with one token per line. I'd like to filter out the rows that contain stop words.

The dataframe looks like:

docID <- c(1,2,2)
token <- c('the', 'cat', 'sat')
count <- c(10,20,30)
df <- data.frame(docID, token, count)

I've tried the below, but get an error:

library(tidyverse)
library(tidytext)
library(topicmodels)
library(stringr)
data('stop_words')
clean_df <- df %>%
  anti_join(stop_words, by=df$token)

Error:

Error: `by` can't contain join column `the`, `cat`, `sat` which is missing from LHS

How can I resolve this?

Body:
When you set up anti_join(), you need to say what the column names are, on the left and right hand sides. In the stop_words data object in tidytext, the column is called word and in your dataframe, it is called token.

library(tidyverse)
library(tidytext)

docID <- c(1, 2, 2, 2, 3)
token <- c("the", "cat", "sat", "on-the-mat", "with3hats")
count <- c(10, 20, 30, 10, 20)
df <- data_frame(docID, token, count)

clean_df <- df %>%
  anti_join(stop_words, by= c("token" = "word"))

clean_df
#> # A tibble: 4 x 3
#>   docID token      count
#>   <dbl> <chr>      <dbl>
#> 1  2.00 cat         20.0
#> 2  2.00 sat         30.0
#> 3  2.00 on-the-mat  10.0
#> 4  3.00 with3hats   20.0

Notice that "the" is now gone because it is in the stop_words dataset.

In a comment, you asked about removing tokens that contain punctuation or numbers. I'd use filter() for this (you can actually use filter() to remove stopwords too, if you prefer.)

clean_df <- df %>%
  filter(!str_detect(token, "[:punct:]|[:digit:]"))

clean_df
#> # A tibble: 3 x 3
#>   docID token count
#>   <dbl> <chr> <dbl>
#> 1  1.00 the    10.0
#> 2  2.00 cat    20.0
#> 3  2.00 sat    30.0

If you want to do both, build up your object with both lines using pipes.


问:
Kivy- Call method outside of class
I have 2 buttons and 2 labels in my .kv file

```<code><Controller>:
    lbl1: first_check
    lbl2: second_check

BoxLayout:
    orientation: 'horizontal'

    Button:
        on_press: root.start_program()
        text: 'Start Program'

    Button:
        on_press: root.stop_program()
        text: "Stop Program"

    Label:
        id: first_check
        text: 'No distance given'

    Label:
        id: second_check
        text: 'No distance given'
</code>```

In the .py file I have the root widget Controller class and some additional functions check_distance and end_goal outside of the class

```<code>def check_distance(dt):
"""The if statements in this block of code will be run if r.dist <= 2700"""
c = Controller()
r.loop()
print(r.dist)
if r.dist <= 2700:
    c.show_dist()
    time.sleep(0.5)
    r.loop()
    if r.dist <= 2700:
        c.lbl2.text = "Below 2700"
        end_goal()

def end_goal():
"""Stops the check_distance function from being called every 2 seconds then
runs the next bit of code"""
    Clock.unschedule(check_distance)
    beepPin.write(1)
    time.sleep(1)
    beepPin.write(0)
    time.sleep(1)
    beepPin.write(1)
    time.sleep(1)
    beepPin.write(0)

class Controller(BoxLayout):
    def __init__(self, **kwargs):
        super(Controller, self).__init__(**kwargs)

def start_program(self):
    """Tells the check_distance function to run every 2 seconds"""
    Clock.schedule_interval(check_distance, 2)

def stop_program(self):
    """Will stop the check_distance function from running"""
    Clock.unschedule(check_distance)
    self.lbl2.text = str(r.dist)

def show_dist(self):
    self.lbl1.text = str(r.dist)

class BaseMotorApp(App):
    def build(self):
        return Controller()

BaseMotorApp().run()
</code>```

When the Start Program button is pushed the check_distance function gets called every 2 seconds. Once the if conditions are met it will run through all the check_distance code. I know this is happening because the end_goal is successfully called. The problem is c.show_dist() is not doing anything and I'm not getting any error. I want it to call the show_dist function in the Controller class. I've even tried to eliminate the show_dist function all together and just typed self.lbl1.text = str(r.dist) in the check_distance function but still nothing. I'm guessing there must be some problem with the way that I am calling this class method. Can someone please help me?

答:
Avoid time.sleep in Kivy applications

The problem that you are encountering was due to time.sleep. You should replace time.sleep with Kivy Clock.schedule_once as in the following exmple.

```<code>def check_distance(dt):
    """The if statements in this block of code will be run if r.dist <= 2700"""
    c = Controller()
    r.loop()
    print(r.dist)
    if r.dist <= 2700:
        c.show_dist()
        Clock.schedule_once(check_distance_assign_label, 0.5)

def check_distance_assign_label(dt):
    r.loop()
    if r.dist <= 2700:
        c.lbl2.text = "Below 2700"
        end_goal()

def end_goal():
    """Stops the check_distance function from being called every 2 seconds then
    runs the next bit of code"""
    Clock.unschedule(check_distance)
    Clock.schedule_once(beepPinWrite(0), 1.0)
    Clock.schedule_once(beepPinWrite(1), 2.0)
    Clock.schedule_once(beepPinWrite(0), 3.0)

def beepPinWrite(index, dt):
    beepPin.write(index)
</code>```

Title: Kivy- Call method outside of class

Body:
I have 2 buttons and 2 labels in my .kv file

<Controller>:
    lbl1: first_check
    lbl2: second_check

BoxLayout:
    orientation: 'horizontal'

    Button:
        on_press: root.start_program()
        text: 'Start Program'

    Button:
        on_press: root.stop_program()
        text: "Stop Program"

    Label:
        id: first_check
        text: 'No distance given'

    Label:
        id: second_check
        text: 'No distance given'

In the .py file I have the root widget Controller class and some additional functions check_distance and end_goal outside of the class

def check_distance(dt):
"""The if statements in this block of code will be run if r.dist <= 2700"""
c = Controller()
r.loop()
print(r.dist)
if r.dist <= 2700:
    c.show_dist()
    time.sleep(0.5)
    r.loop()
    if r.dist <= 2700:
        c.lbl2.text = "Below 2700"
        end_goal()

def end_goal():
"""Stops the check_distance function from being called every 2 seconds then
runs the next bit of code"""
    Clock.unschedule(check_distance)
    beepPin.write(1)
    time.sleep(1)
    beepPin.write(0)
    time.sleep(1)
    beepPin.write(1)
    time.sleep(1)
    beepPin.write(0)

class Controller(BoxLayout):
    def __init__(self, **kwargs):
        super(Controller, self).__init__(**kwargs)

def start_program(self):
    """Tells the check_distance function to run every 2 seconds"""
    Clock.schedule_interval(check_distance, 2)

def stop_program(self):
    """Will stop the check_distance function from running"""
    Clock.unschedule(check_distance)
    self.lbl2.text = str(r.dist)

def show_dist(self):
    self.lbl1.text = str(r.dist)

class BaseMotorApp(App):
    def build(self):
        return Controller()

BaseMotorApp().run()

When the Start Program button is pushed the check_distance function gets called every 2 seconds. Once the if conditions are met it will run through all the check_distance code. I know this is happening because the end_goal is successfully called. The problem is c.show_dist() is not doing anything and I'm not getting any error. I want it to call the show_dist function in the Controller class. I've even tried to eliminate the show_dist function all together and just typed self.lbl1.text = str(r.dist) in the check_distance function but still nothing. I'm guessing there must be some problem with the way that I am calling this class method. Can someone please help me?

Body:
Avoid time.sleep in Kivy applications

The problem that you are encountering was due to time.sleep. You should replace time.sleep with Kivy Clock.schedule_once as in the following exmple.

def check_distance(dt):
    """The if statements in this block of code will be run if r.dist <= 2700"""
    c = Controller()
    r.loop()
    print(r.dist)
    if r.dist <= 2700:
        c.show_dist()
        Clock.schedule_once(check_distance_assign_label, 0.5)

def check_distance_assign_label(dt):
    r.loop()
    if r.dist <= 2700:
        c.lbl2.text = "Below 2700"
        end_goal()

def end_goal():
    """Stops the check_distance function from being called every 2 seconds then
    runs the next bit of code"""
    Clock.unschedule(check_distance)
    Clock.schedule_once(beepPinWrite(0), 1.0)
    Clock.schedule_once(beepPinWrite(1), 2.0)
    Clock.schedule_once(beepPinWrite(0), 3.0)

def beepPinWrite(index, dt):
    beepPin.write(index)


问:
CHANGE IN WSDL AND ERROR IN SOAPUI PROJECT
I created a Soap Project for a group of soap web services in my test region where i can run the project repeatedly just by changing input data/test data(here my wsdl was updated in September in Testregion).

Now,my test region has got an Wsdl Updated(september wsdl does not exists in test now) and when i try to run soap project(built using sep wsdl).its giving
me below error

```<code>   <?xml version="1.0" encoding="UTF-8"?>
   <env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org   /2001/XMLSchema-instance" xmlns:enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns0="http://konnex.aarp.org/types/SwordCiboodleServicesSecure" env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
     <env:Body>
          <env:Fault>
               <faultcode>env:Server</faultcode>
               <faultstring>JAXRPC.TIE.04: Internal Server Error   (JAXRPCTIE01: caught exception while handling request: java.lang.NullPointerException)</faultstring>
          </env:Fault>
     </env:Body>
  </env:Envelope>
</code>```

SO my question is is there any way to use/run the same project with new updated WSDL

答:
If you are using SoapUI then there is an option to update WSDL definitions by right clicking on the WSDL you imported and choosing update definition. From your description the option "Recreate existing requests with new schema" sounds like what you want. </p>

<p>The following link gives a description of what the options are and example situations for using them https://dzone.com/articles/soapui-tip-options-refreshing </p>

Body:
I created a Soap Project for a group of soap web services in my test region where i can run the project repeatedly just by changing input data/test data(here my wsdl was updated in September in Testregion).

Now,my test region has got an Wsdl Updated(september wsdl does not exists in test now) and when i try to run soap project(built using sep wsdl).its giving
me below error

   <?xml version="1.0" encoding="UTF-8"?>
   <env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org   /2001/XMLSchema-instance" xmlns:enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns0="http://konnex.aarp.org/types/SwordCiboodleServicesSecure" env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
     <env:Body>
          <env:Fault>
               <faultcode>env:Server</faultcode>
               <faultstring>JAXRPC.TIE.04: Internal Server Error   (JAXRPCTIE01: caught exception while handling request: java.lang.NullPointerException)</faultstring>
          </env:Fault>
     </env:Body>
  </env:Envelope>

SO my question is is there any way to use/run the same project with new updated WSDL

Body:
If you are using SoapUI then there is an option to update WSDL definitions by right clicking on the WSDL you imported and choosing update definition. From your description the option "Recreate existing requests with new schema" sounds like what you want.

The following link gives a description of what the options are and example situations for using them https://dzone.com/articles/soapui-tip-options-refreshing


问:
Clearing attributes set in JSON file
How one does remove attribte set in JSON data file (-j used during chef-client run)? Lets say, I needed to override attribute:

```<code>default['param']['myParam'] = 'A'
</code>```

So I've created JSON file:

```<code>{
 "param" : {
    "myParam" : "B"
 }
}
</code>```

In the next version of cookbook, this parameter gets new value: C. I'm removing it from JSON datafile and want to use this new value, but Chef stores B even when it isn't in JSON file.

How can I ensure that Chef will ignore old attributes?

答: Attributes set via -j get put in the normal level, which sticks around until cleared. This is why we do not recommend using the normal level or -j attributes. You'll have to clear them manually using tools like knife node edit.

Title: Clearing attributes set in JSON file

Body:
How one does remove attribte set in JSON data file (-j used during chef-client run)? Lets say, I needed to override attribute:

default['param']['myParam'] = 'A'

So I've created JSON file:

{
 "param" : {
    "myParam" : "B"
 }
}

In the next version of cookbook, this parameter gets new value: C. I'm removing it from JSON datafile and want to use this new value, but Chef stores B even when it isn't in JSON file.

How can I ensure that Chef will ignore old attributes?


问:
How to force tag helper for hidden fields to render bool value in lower case
I have a view model with a simple bool-property like this one:

```<code>public bool HasAnyProductsThatRequirePhoneNumber { get; set; }
</code>```

I'm using a tag helper to generate a HiddenField that will contain this value as in the following code:

```<code><input type="hidden"
       asp-for="@this.Model.HasAnyProductsThatRequirePhoneNumber" />
</code>```

When the page is rendered I obtain the following HTML-Code:

```<code><input type="hidden"
       id="HasAnyProductsThatRequirePhoneNumber"
       name="HasAnyProductsThatRequirePhoneNumber"
       value="True" />
</code>```

As you can see, the "value"-attribute has been rendered in uppercase (with a big T).

Is there any way to render it lower case? Of course I can't use something like .ToString().ToLower() since as you can see I'm specifying only the asp-for attribute manually while the value-attribute is filled automatically.

答:
No. You cannot!

The code will call the ToString method on the boolean expression/proprety. The ToString method inside boolean always returns True or False

```<code>public override String ToString()
{
   if (false == m_value)
   {
       return FalseLiteral;
   }
   return TrueLiteral;
 }
</code>```

Where TrueLiteral and FalseLiteral are two variables with values such as True and False

```<code>internal const String TrueLiteral  = "True";
internal const String FalseLiteral = "False";
</code>```

But that does not stop you from rendering the value as true or false. All the tag helper does is, render the markup for a input. So in your case, you can simply replace the call to the tag helper with pure html and setting the value of the input manually.

```<code> <input type="hidden"
    id="HasAnyProductsThatRequirePhoneNumber"
    name="HasAnyProductsThatRequirePhoneNumber"
   value="@Model.HasAnyProductsThatRequirePhoneNumber.ToString().ToLower()">
</code>```

Body:
I have a view model with a simple bool-property like this one:

public bool HasAnyProductsThatRequirePhoneNumber { get; set; }

I'm using a tag helper to generate a HiddenField that will contain this value as in the following code:

<input type="hidden"
       asp-for="@this.Model.HasAnyProductsThatRequirePhoneNumber" />

When the page is rendered I obtain the following HTML-Code:

<input type="hidden"
       id="HasAnyProductsThatRequirePhoneNumber"
       name="HasAnyProductsThatRequirePhoneNumber"
       value="True" />

As you can see, the "value"-attribute has been rendered in uppercase (with a big T).

Is there any way to render it lower case? Of course I can't use something like .ToString().ToLower() since as you can see I'm specifying only the asp-for attribute manually while the value-attribute is filled automatically.

Body:
No. You cannot!

The code will call the ToString method on the boolean expression/proprety. The ToString method inside boolean always returns True or False

public override String ToString()
{
   if (false == m_value)
   {
       return FalseLiteral;
   }
   return TrueLiteral;
 }

Where TrueLiteral and FalseLiteral are two variables with values such as True and False

internal const String TrueLiteral  = "True";
internal const String FalseLiteral = "False";

But that does not stop you from rendering the value as true or false. All the tag helper does is, render the markup for a input. So in your case, you can simply replace the call to the tag helper with pure html and setting the value of the input manually.

 <input type="hidden"
    id="HasAnyProductsThatRequirePhoneNumber"
    name="HasAnyProductsThatRequirePhoneNumber"
   value="@Model.HasAnyProductsThatRequirePhoneNumber.ToString().ToLower()">


问:
Optimizing tensorflow to CPU use
I have a model that needs to be optimized to CPU.

Currently the model takes a 1024 x 1024 bytes data.

```<code>images = img[y:y+1024,x:x+1024,:]
</code>```

As per this document, they want to change the default tensorflow data format from NHCW to NCHW format.

How can I transform from NHWC to NCHW format?

https://software.intel.com/en-us/articles/tensorflow-optimizations-on-modern-intel-architecture

答:
As per this document, they want to change the default tensorflow data format from NHCW to NCHW format.

Actually, I've never seen any Tensorflow function that supports NHCW format. For example, tf.nn.conv2d and tf.nn.conv2d_transpose support NHWC (current default) and NCHW format. tf.nn.max_pool supports  NHWC, NCHW and NCHW_VECT_C (the last one is the most performant tensor format for cudnn6's quantized convolution, similar to NCHW).

How can I transform from NHCW to NCHW format?

But this transformation is possible, e.g. via tf.transpose that works with high-dimensional tensors as well:

# NHCW
original = tf.placeholder(dtype=tf.float32, shape=[None, 1024, 3, 1024])
# NCHW: swap 1 and 2 axis
transformed = tf.transpose(original, perm=[0, 2, 1, 3])
```

You can also do this in numpy via np.swapaxes(array, 1, 2).

Title: Optimizing tensorflow to CPU use

Body:
I have a model that needs to be optimized to CPU.

Currently the model takes a 1024 x 1024 bytes data.

images = img[y:y+1024,x:x+1024,:]

As per this document, they want to change the default tensorflow data format from NHCW to NCHW format.

How can I transform from NHWC to NCHW format?

https://software.intel.com/en-us/articles/tensorflow-optimizations-on-modern-intel-architecture

Body:
As per this document, they want to change the default tensorflow data format from NHCW to NCHW format.

Actually, I've never seen any Tensorflow function that supports NHCW format. For example, tf.nn.conv2d and tf.nn.conv2d_transpose support NHWC (current default) and NCHW format. tf.nn.max_pool supports  NHWC, NCHW and NCHW_VECT_C (the last one is the most performant tensor format for cudnn6's quantized convolution, similar to NCHW).

How can I transform from NHCW to NCHW format?

But this transformation is possible, e.g. via tf.transpose that works with high-dimensional tensors as well:

# NHCW
original = tf.placeholder(dtype=tf.float32, shape=[None, 1024, 3, 1024])
# NCHW: swap 1 and 2 axis
transformed = tf.transpose(original, perm=[0, 2, 1, 3])

You can also do this in numpy via np.swapaxes(array, 1, 2).


问:
How to simplify an account code?
I am making an account code in python and it works but it is really long and I want to know if there is a way to shorten it. Here is my code:

```<code>user1 = "Jeff"
user2 = "Bob"

password1 = "Password"
password2 = "Lol"

username = input("Login: >> ")
password = input("Password: >> ")

if username == user1:
    if password == password1:
        print ("Access granted")
        print ("Welcome to the system!")
        home()

    else:
        print ("Access denied")
        print ("Try again!")
        print ("\n")
        time.sleep(2)
        login()

elif username == user2:
    if password == password2:
        print ("Access granted")
        print ("Welcome to the system!")
        home()
    else:
        print ("Access denied")
        print ("Try again!")
        print ("\n")
        time.sleep(2)
        login()

else:
    print ("Access denied")
    print ("Try again!")
    print ("\n")
    time.sleep(2)
    login()
</code>```

The more accounts I create the longer longer it will get. Is there a way to shorten or simplify this?

答:
Here is a version of your program that uses a dictionary to store user names with their associated passwords.  This way, you can add more users and passwords to the users dictionary, and you do not need to add any more code.

```<code>import time

users = {
    "Jeff": "Password",
    "Bob": "Lol"}

def login():
    username = input("Login: >> ")
    password = input("Password: >> ")
    if username in users and password == users[username]:
        print("Access granted")
        print("Welcome to the system!")
        return True

    print("Access denied")
    print("Try again!")
    print()
    return False

while not login():
    pass

home()
</code>```

Title: How to simplify an account code?

Body:
I am making an account code in python and it works but it is really long and I want to know if there is a way to shorten it. Here is my code:

user1 = "Jeff"
user2 = "Bob"

password1 = "Password"
password2 = "Lol"

username = input("Login: >> ")
password = input("Password: >> ")

if username == user1:
    if password == password1:
        print ("Access granted")
        print ("Welcome to the system!")
        home()

    else:
        print ("Access denied")
        print ("Try again!")
        print ("\n")
        time.sleep(2)
        login()

elif username == user2:
    if password == password2:
        print ("Access granted")
        print ("Welcome to the system!")
        home()
    else:
        print ("Access denied")
        print ("Try again!")
        print ("\n")
        time.sleep(2)
        login()

else:
    print ("Access denied")
    print ("Try again!")
    print ("\n")
    time.sleep(2)
    login()

The more accounts I create the longer longer it will get. Is there a way to shorten or simplify this?

Body:
Here is a version of your program that uses a dictionary to store user names with their associated passwords.  This way, you can add more users and passwords to the users dictionary, and you do not need to add any more code.

import time

users = {
    "Jeff": "Password",
    "Bob": "Lol"}

def login():
    username = input("Login: >> ")
    password = input("Password: >> ")
    if username in users and password == users[username]:
        print("Access granted")
        print("Welcome to the system!")
        return True

    print("Access denied")
    print("Try again!")
    print()
    return False

while not login():
    pass

home()


问:
Is SpringData's DomainClassConverter supposed to work with Hibernate proxies?
My team maintains a web app built with Spring Boot, Spring Data, Thymeleaf, and JPA/Hibernate. We recently hit an issue with a Thymeleaf template SpringEL expression failing to evaluate due to a type conversion problem:

Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [com.xyz.app.model.Employee_$$_jvst7ca_34] to type [java.lang.String]

The expression is ${{employee}} where employee is an entity placed into the model by a Spring controller. The employee entity is retrieved with a simple call to a Spring Data repository:

```<code>@ModelAttribute("employee")
public Employee getEmployee(@PathVariable("employeeId") long employeeId) {
    return employeeRepository.findOne(employeeId);
}
</code>```

While debugging, I noticed that the Employee entity returned is actually a Hibernate proxy, as you can see in the exception cause from the log - the Employee class has the javassist suffix: _$$_jvst7ca_34

Spring Data registers DomainClassConverter with Spring's GenericConversionService which should convert an entity to an ID for an expression like ${{employee}} when the @EnableSpringDataWebSupport annotation is present.  Spring Boot provides an autoconfiguration class SpringDataWebAutoConfiguration which enables this by default. I confirmed that this autoconfiguration class is applied by our application.

I also confirmed through debugging that the GenericConversionService retrieves the DomainClassConverter.ToIdConverter when attempting to convert from Employee_$$_jvst7ca_34 to String. However DomainClassConverter.ToIdConverter.matches(sourceType, targetType) returns false, so the converter is not used. It returns false because it cannot find a repository in Repositories with the type Employee_$$_jvst7ca_34. I see with the debugger that the only Employee repository in the Repositories list is for Employee.

Is this a bug in DomainClassConverter? Shouldn't it be capable of retrieving a repository for a proxy? It seems that proxies should be quite common since any entity with a lazy collection (the recommended collection type) will come back as a proxy.  Or are we doing something wrong?  Any hints would be very appreciated!

答: It turns out this was a bug in Spring Data Commons. The issue has now been addressed and in future releases it should be possible to convert a proxy.</p>

Body:
My team maintains a web app built with Spring Boot, Spring Data, Thymeleaf, and JPA/Hibernate. We recently hit an issue with a Thymeleaf template SpringEL expression failing to evaluate due to a type conversion problem:

Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [com.xyz.app.model.Employee_$$_jvst7ca_34] to type [java.lang.String]

The expression is ${{employee}} where employee is an entity placed into the model by a Spring controller. The employee entity is retrieved with a simple call to a Spring Data repository:

@ModelAttribute("employee")
public Employee getEmployee(@PathVariable("employeeId") long employeeId) {
    return employeeRepository.findOne(employeeId);
}

While debugging, I noticed that the Employee entity returned is actually a Hibernate proxy, as you can see in the exception cause from the log - the Employee class has the javassist suffix: _$$_jvst7ca_34

Spring Data registers DomainClassConverter with Spring's GenericConversionService which should convert an entity to an ID for an expression like ${{employee}} when the @EnableSpringDataWebSupport annotation is present.  Spring Boot provides an autoconfiguration class SpringDataWebAutoConfiguration which enables this by default. I confirmed that this autoconfiguration class is applied by our application.

I also confirmed through debugging that the GenericConversionService retrieves the DomainClassConverter.ToIdConverter when attempting to convert from Employee_$$_jvst7ca_34 to String. However DomainClassConverter.ToIdConverter.matches(sourceType, targetType) returns false, so the converter is not used. It returns false because it cannot find a repository in Repositories with the type Employee_$$_jvst7ca_34. I see with the debugger that the only Employee repository in the Repositories list is for Employee.

Is this a bug in DomainClassConverter? Shouldn't it be capable of retrieving a repository for a proxy? It seems that proxies should be quite common since any entity with a lazy collection (the recommended collection type) will come back as a proxy.  Or are we doing something wrong?  Any hints would be very appreciated!


问:
Does memoization works with active record relations?
Let's say i have a method in my model as below.

```<code>def all_users
  @users ||= User.all
end
</code>```

and I have other method in my model where i am doing all_users.where(id: 123) for multiple different ids. Will it execute a query/ hit to db everytime or it will fetch the record directly from the cached resultset.

答:
User.all returns an active record relation - it doesn't fetch any data until you try and do something with it (eg call array-like methods on it). When that happens, rails will load the data for the relation, if it is not already loaded.

So if you do things like

```<code>all_users.sample(5)
all_users.detect {|record| ... }
</code>```

then you'll only fetch from the data base once.

However if you use methods such as where, joins, ... that return a new relation then those relations will need to hit the database if their data is needed.

```<code>all_users.where(id: 1).first
all_users.where(id: 2).first
all_users.where(id: 3).first
</code>```

Would execute 3 queries for example.

If you have a list of ids it would be far better to do User.find(ids) (or User.where(id: ids) if you want to allow missing values).

Body:
Let's say i have a method in my model as below.

def all_users
  @users ||= User.all
end

and I have other method in my model where i am doing all_users.where(id: 123) for multiple different ids. Will it execute a query/ hit to db everytime or it will fetch the record directly from the cached resultset.

Body:
User.all returns an active record relation - it doesn't fetch any data until you try and do something with it (eg call array-like methods on it). When that happens, rails will load the data for the relation, if it is not already loaded.

So if you do things like

all_users.sample(5)
all_users.detect {|record| ... }

then you'll only fetch from the data base once.

However if you use methods such as where, joins, ... that return a new relation then those relations will need to hit the database if their data is needed.

all_users.where(id: 1).first
all_users.where(id: 2).first
all_users.where(id: 3).first

Would execute 3 queries for example.

If you have a list of ids it would be far better to do User.find(ids) (or User.where(id: ids) if you want to allow missing values).


问:
boost::asio, threads and synchronization
This is somewhat related to this question, but I think I need to know a little bit more.  I've been trying to get my head around how to do this for a few days (whilst working on other parts), but the time has come for me to bite the bullet and get multi-threaded.  Also, I'm after a bit more information than the question linked.

Firstly, about multi-threading.  As I have been testing my code, I've not bothered with any multi-threading.  It's just a console application that starts a connection to a test server and everything else is then handled.  The main loop is this:

```<code>while(true)
{
    Root::instance().performIO(); // calls io_service::runOne();
}
</code>```

When I write my main application, I'm guessing this solution won't be acceptable (as it would have to be called in the message loop which, whilst possible, would have issues when the message queue blocks waiting for a message.  You could change it so that the message-loop doesn't block, but then isn't that going to whack the CPU usage through the roof?)

The solution it seems is to throw another thread at it.  Okay, fine.  But then I've read that io_service::run() returns when there is no work to do.  What is that?  Is that when there's no data, or no connections?  If at least one connection exists does it stay alive?  If so, that's not so much of a problem as I only have to start up a new thread when the first connection is made and I'm happy if it all stops when there is nothing going on at all.  I guess I am confused by the definition of 'no work to do'.

Then I have to worry about synchronizing my boost thread with my main GUI thread.  So, I guess my questions are:

What is the best-practice way of using boost::asio in a client application with regard to threads and keeping them alive?

When writing to a socket from the main thread to the IO thread, is synchronization achieved using boost::asio::post, so that the call happens later in the io_service?

When data is received, how do people get the data back to the UI thread?  In the past when I used completion ports, I made a special event that could post the data back to the main UI thread using a ::SendMessage.  It wasn't elegant, but it worked.

I'll be reading some more today, but it would be great to get a heads up from someone who has done this already.  The Boost::asio documentation isn't great, and most of my work so far has been based on a bit of the documentation, some trial/error, some example code on the web.

答:
boost::io_service::run() will return only when there's nothing to do, so no async operations are pending, e.g. async accept/connection, async read/write or async timer wait. so before calling io_service::run() you first have to start any async op.

i haven't got do you have console or GUI app? in any case multithreading looks like a overkill. you can use Asio in conjunction with your message loop. if it's win32 GUI you can call io_service::run_one() from you OnIdle() handler. in case of console application you can setup deadline_timer that regularly checks (every 200ms?) for user input and use it with io_service::run(). everything in single thread to greatly simplify the solution

Body:
This is somewhat related to this question, but I think I need to know a little bit more.  I've been trying to get my head around how to do this for a few days (whilst working on other parts), but the time has come for me to bite the bullet and get multi-threaded.  Also, I'm after a bit more information than the question linked.

Firstly, about multi-threading.  As I have been testing my code, I've not bothered with any multi-threading.  It's just a console application that starts a connection to a test server and everything else is then handled.  The main loop is this:

while(true)
{
    Root::instance().performIO(); // calls io_service::runOne();
}

When I write my main application, I'm guessing this solution won't be acceptable (as it would have to be called in the message loop which, whilst possible, would have issues when the message queue blocks waiting for a message.  You could change it so that the message-loop doesn't block, but then isn't that going to whack the CPU usage through the roof?)

The solution it seems is to throw another thread at it.  Okay, fine.  But then I've read that io_service::run() returns when there is no work to do.  What is that?  Is that when there's no data, or no connections?  If at least one connection exists does it stay alive?  If so, that's not so much of a problem as I only have to start up a new thread when the first connection is made and I'm happy if it all stops when there is nothing going on at all.  I guess I am confused by the definition of 'no work to do'.

Then I have to worry about synchronizing my boost thread with my main GUI thread.  So, I guess my questions are:

What is the best-practice way of using boost::asio in a client application with regard to threads and keeping them alive?

When writing to a socket from the main thread to the IO thread, is synchronization achieved using boost::asio::post, so that the call happens later in the io_service?

When data is received, how do people get the data back to the UI thread?  In the past when I used completion ports, I made a special event that could post the data back to the main UI thread using a ::SendMessage.  It wasn't elegant, but it worked.

I'll be reading some more today, but it would be great to get a heads up from someone who has done this already.  The Boost::asio documentation isn't great, and most of my work so far has been based on a bit of the documentation, some trial/error, some example code on the web.