I use a Chart to Display Progress of Activity on ms-access 2007 with VBA, I used to work with PivotCharts wich was fast but not really editable. I need to only display the past months and make invisibles points for the rest of the year.
My Chart is display with 2 Series of 300 points (granularity increased), but I only show Data Labels once in a month.
I wasn't able to edit point by point with Pivot Chart so I moved to a classic oldStyle Chart.
My problem is that my edit is very slow, I've read about many things about VBA optimization but nothing done the trick
I measured 20 seconds for each curve it's not "acceptable" for my hierarchy.
I was thinking about multi-threading but it's way too much work for a so small benefit (%4? or %8?)
(FYI Calculation of points and so on is done before the opening of the Form and is doing great)
Here is my code of this Slow Chart Edition :
Dim intPntCount As Integer
Dim intTmp As Integer
Dim oSeries As Object
Dim colSeries As SeriesCollection
Dim oPnt As Object
Dim intCptSeries As Byte
Dim booPreviousZero As Boolean
Dim startDate, endDate As Date
Dim lngWhite, LngBlack As Long
lngWhite = RGB(255, 255, 255)
LngBlack = RGB(0, 0, 0)
linPlanned.BorderColor = RGB(251, 140, 60)
linCompleted.BorderColor = RGB(52, 84, 136)
lblUnit.Left = 1248 'use fctgetabsciisa chProgressFixs.Axes(2).MaximumScale / 80
With Me.chProgressFixs
startDate = Now
.BackColor = lngWhite
intCptSeries = 0
'colSeries = .SeriesCollection
For Each oSeries In .SeriesCollection
intCptSeries = intCptSeries + 1
Debug.Print "Series" & intCptSeries
booPreviousZero = True
intPntCount = 1
For Each oPnt In oSeries.Points
oPnt.ApplyDataLabels
If oPnt.DataLabel.Caption = "0" Then
oPnt.Border.Weight = 1
oPnt.DataLabel.Caption = vbNullString
If booPreviousZero = False Then
oPnt.Border.Color = lngWhite
booPreviousZero = True
Else
oPnt.Border.Color = LngBlack
End If
Else
booPreviousZero = False
oPnt.Border.Weight = 4
oPnt.DataLabel.Font.Size = 14
Select Case intCptSeries
Case 1: oPnt.Border.Color = linPlanned.BorderColor
Case 2: oPnt.Border.Color = linCompleted.BorderColor
End Select
If ((intPntCount + 30) / 30 <> Int((intPntCount + 30) / 30)) Then
If (intPntCount < oSeries.Points.Count) Then
If (intPntCount <> IntLastDispDay - 1) Then
oPnt.DataLabel.Caption = vbNullString
Else
oPnt.DataLabel.Font.Size = 20
End If
End If
End If
End If
intPntCount = intPntCount + 1
Next
Debug.Print DateDiff("s", startDate, Now)
Next
Me.TimerInterval = 1
End With
Thanks all for your help
Maybe you need to avoid screen refresh with:
Application.ScreenUpdating = False
and then
Application.ScreenUpdating = true
when finished. It also be helpful if you use \ insted of / when dividing, if you don't care about working only with integers. Try it.
Maybe you should replace:
If ((intPntCount + 30) / 30 <> Int((intPntCount + 30) / 30)) Then
with something like
If (((intPntCount + 30) MOD 30) > 0 ) Then
and measure the time of execution. Another thing about your code is that:
oPnt.DataLabel.Font.Size = 14
...maybe should be inside the if's trying to avoid rewrite the property two times. Try something like:
If (((intPntCount + 30) MOD 30) > 0 ) Then
If (intPntCount < oSeries.Points.Count) Then
If (intPntCount <> IntLastDispDay - 1) Then
oPnt.DataLabel.Caption = vbNullString
oPnt.DataLabel.Font.Size = 14
Else
oPnt.DataLabel.Font.Size = 20
End If
Else
oPnt.DataLabel.Font.Size = 14
End If
Else
oPnt.DataLabel.Font.Size = 14
End If
Even it would be a very very little improvement to precalculate
(intPntCount + 30)
in a variable after
intPntCount = intPntCount + 1
...and use something like:
dim intPntCountSum= 0
(...)
End If
intPntCount = intPntCount + 1
intPntCountSum=intPntCount + 30
Next
Finally, if you don't need the debug info, it would be a good thing to delete the lines:
Debug.Print "Series" & intCptSeries
and
Debug.Print DateDiff("s", startDate, Now)
I hope it help.
Related
I have an SSRS report that uses the following code to calculate some statistics based on parameters selected by the user.
When this runs in Chrome on a machine with en-US localization, the output comes out correct.
When in Chrome in a machine with es-MX localization, the output is off because the decimal becomes a thousands separator (comma) and the thousands separator (comma) becomes a decimal.
Oddly enough, when I run in Edge on the same machine with es-MX, the output is correct.
How do I handle the localization of number formatting within the code embedded in the SSRS report?
Function GetDataSetLabelFromValue
Public function GetDataSetLabelFromValue() as decimal
dim i as integer
dim rBar as decimal
dim processSigma as decimal
dim d2 as decimal
dim restartLow as integer
restartLow = 0
d2 = 1.128
i = 0
rBar = 0.0
IF Report.Parameters!UseRestart.Value =FALSE THEN
restartLow = 0
ELSE
For i =0 to (Report.Parameters!RestartFilter.COUNT() - 1)
IF CBool(Report.Parameters!RestartFilter.Label(i)) = 0 THEN
restartLow = i + 1
END IF
Next i
END IF
IF Report.Parameters!LastBatch.Value = TRUE THEN
for i = restartLow to (Report.Parameters!PSigma.Count() - 2)
rBar = rBar + ABS(Report.Parameters!PSigma.Label(i) - Report.Parameters!PSigma.Label(i+1))
next i
ELSE
for i = restartLow to (Report.Parameters!PSigma.Count() - 3)
rBar = rBar + ABS(Report.Parameters!PSigma.Label(i) - Report.Parameters!PSigma.Label(i+1))
next i
END IF
IF (Report.Parameters!PSigma.Count() - (restartLow))=0 OR (Report.Parameters!PSigma.Count() - (restartLow) - 1)=0 THEN
rBar = 0
ELSE
IF Report.Parameters!LastBatch.Value = TRUE THEN
rBar = rBar / (Report.Parameters!PSigma.Count() - (restartLow))
ELSE
rBar = rBar / (Report.Parameters!PSigma.Count()-restartLow-1)
END IF
END IF
processSigma = rBar / d2
GetDataSetLabelFromValue = processSigma
End Function
Function GetAverageValue
Public function GetAverageValue() as decimal
dim i as integer
dim average as decimal
dim restartLow as integer
restartLow = 0
i = 0
average = 0.0
IF Report.Parameters!UseRestart.VALUE =FALSE THEN
restartLow = 0
ELSE
For i =0 to (Report.Parameters!RestartFilter.COUNT() - 1)
IF CBool(Report.Parameters!RestartFilter.Label(i)) = 0 THEN
restartLow = i + 1
END IF
Next i
END IF
IF Report.Parameters!LastBatch.Value = TRUE THEN
for i = restartLow to (Report.Parameters!PSigma.Count() - 1)
average = average + (CDEC(Report.Parameters!PSigma.Label(i)))
next i
ELSE
for i = restartLow to (Report.Parameters!PSigma.Count() - 2)
average = average + (CDEC(Report.Parameters!PSigma.Label(i)))
next i
END IF
IF (Report.Parameters!PSigma.Count() - (restartLow))=0 OR (Report.Parameters!PSigma.Count() - (restartLow) - 1)=0 THEN
average = 0
ELSE
IF Report.Parameters!LastBatch.Value = TRUE THEN
average = average / (Report.Parameters!PSigma.Count() - (restartLow))
ELSE
average = average / (Report.Parameters!PSigma.Count()-restartLow-1)
END IF
END IF
GetAverageValue = average
End Function
EDIT: I Have figured out what I needed and placed the new portions of code in asterisks
I am using VBA in Access 2003 and have the following question:
I have some code that does a mailmerge to create labels, and it works fine on its own. I have been asked to see if it is possible to have the labels run down the cells and then across. Right now they fill up across then run down to the next row. If it is possible, would it be best to do it before the mailmerge executes, or do I do it in the loop that I have following the mailmerge? It is very important that the "5660 EasyPeel Address Labels" formatting stays the same. I have placed my coding below.
With oDoc.MailMerge
With .Fields
.Add oApp.Selection.Range, "FullAddress"
oApp.Selection.TypeParagraph
End With
Set oAutoText = oApp.NormalTemplate.AutoTextEntries.Add("MyLabelLayout", oDoc.Content)
oDoc.Content.Delete
.MainDocumentType = wdMailingLabels
.OpenDataSource Name:=strTxtFile, ConfirmConversions:=False, AddToRecentFiles:=False
oApp.MailingLabel.CreateNewDocument Name:="5660 Easy Peel Address Labels", Address:="", Autotext:="MyLabelLayout"
.Destination = wdSendToNewDocument
.Execute
oAutoText.Delete
'Loop through and add cell padding to each table.
intTblCount = oApp.ActiveDocument.Tables.Count
Do Until intTblCount = 0
DoEvents
oApp.ActiveDocument.Tables(intTblCount).TopPadding = PixelsToPoints(5, True)
DoEvents
oApp.ActiveDocument.Tables(intTblCount).Range.Select
With Selection
.Font.Size = 9
.Font.Name = "Janson Text LT Std"
.ParagraphFormat.LineSpacing = LinesToPoints(0.8)
.ParagraphFormat.SpaceBefore = 5
.ParagraphFormat.SpaceAfter = 5
.MoveRight wdCharacter, 5
End With
***Call TransposeTable***
DoEvents
intTblCount = intTblCount - 1
Loop
End With
*** Sub TransposeTable() 'Edited Sub from the Sub Written By Helmut Weber, MVP WordVBA
Dim C As Long ' column
Dim R As Long ' row
Dim x As Long ' just a counter
Dim y As Long ' just a counter
Dim z As Long ' just a counter
'Dim d As Long ' just a counter
Dim STempo As String
Dim sArr() As String
Dim NoGoArray As Variant: NoGoArray = Array(2, 4, 7, 9, 12, 14, 17, 19, 22, 24, 27, 29, 32, 34, 37, 39, 42, 44, 47, 49)
With Selection
.Collapse
With .Tables(1)
C = .Columns.Count
R = .Rows.Count
ReDim sArr(1 To .Range.Cells.Count)
For x = 1 To UBound(sArr)
If IsInArray(x, NoGoArray) Then
GoTo LoopContinue
Else
STempo = .Range.Cells(x).Range.Text
STempo = Left(STempo, (Len(STempo) - 2))
sArr(x) = STempo
'GoTo LoopContinue
End If
LoopContinue:
Next
'--------------------------
' Transpose Table Content
'--------------------------
C = .Columns.Count
R = .Rows.Count
x = 0
For y = 1 To C
For z = 1 To R
If IsOdd(y) Then
x = x + 1
If IsInArray(x, NoGoArray) Then
x = x + 1
.Cell(z, y).Range.Text = sArr(x)
Else
.Cell(z, y).Range.Text = sArr(x)
End If
End If
Next
Next
End With
End With
Erase NoGoArray
End Sub
Public Function IsOdd(ByVal Number As Long) As Boolean
IsOdd = (Number Mod 2 = 1)
End Function
Private Function IsInArray(valToBeFound As Variant, arr As Variant) As Boolean
'DEVELOPER: Ryan Wells (wellsr.com)
'DESCRIPTION: Function to check if a value is in an array of values
'INPUT: Pass the function a value to search for and an array of values of any data type.
'OUTPUT: True if is in array, false otherwise
Dim element As Variant
On Error GoTo IsInArrayError: 'array is empty
For Each element In arr
If element = valToBeFound Then
IsInArray = True
Exit Function
End If
Next element
Exit Function
IsInArrayError:
On Error GoTo 0
IsInArray = False
End Function ***
i am totally stuck with this error, please do help me..
i create a json file, user can select from start date to end date..
so button1 function as to generate the file..
the program goes well until i select a larger data to generate.. then this memory error comes out.. Here is my code:
Using writer As JsonWriter = New JsonTextWriter(sw)
writer.Formatting = Formatting.Indented
With writer
.WriteStartObject()
.WritePropertyName("LiveValue")
.WriteStartArray()
Do
liveValue.Time_Stamp = u
liveValue.Current = Generator.Next(MyMin_Current, MyMax_Current + 1)
liveValue.Voltage = Generator.Next(MyMin_Voltage, MyMax_Voltage + 1)
liveValue.Power = liveValue.Current * liveValue.Voltage
.WriteStartObject()
.WritePropertyName("ID")
.WriteValue(i)
.WritePropertyName("TimeStamp")
.WriteValue(liveValue.Time_Stamp)
.WritePropertyName("MotorID")
.WriteValue(liveValue.MotorID)
.WritePropertyName("Current")
.WriteValue(liveValue.Current)
.WritePropertyName("Voltage")
.WriteValue(liveValue.Voltage)
.WritePropertyName("Power")
.WriteValue(liveValue.Power)
.WriteEndObject()
i = i + 1
If liveValue.MotorID < 20 Then
liveValue.MotorID = liveValue.MotorID + 1
Else
liveValue.MotorID = 1
End If
'If endTime > startTime Then
' liveV.Time_Stamp = u.AddMinutes(+1)
'Else
' liveV.Time_Stamp = endTime
'End If
'(Time Stamp) Time changed every 7secs
If i = w Then
u = u.AddMinutes(+1)
w = w + 20
End If
Loop Until (liveValue.Time_Stamp = endTime)
.WriteEndArray()
.WriteEnd()
End With
file1.WriteLine(sb.ToString)
pBar.Style = ProgressBarStyle.Continuous
End Using
please do help me to solve it..Thank you
I am trying to import data to a table. Basically its a MCQs. All my questions are having superscripts and subscripts, for example X2 , and log52....
I have more than 2000 records, i have to import it. But after importing it comes in plain format, not taking powers. My DB is MYSQL (UTF-8)
Here is the example data
If log5 2, log5 (2x - 5) and log 5(2x - 7/2) are in AP , then x is equal to
after impoting it looks like above, but actually it should be
If log5 2, log5 (2x - 5) and log 5(2x - 7/2) are in AP , then x is equal to
Somebody plz suggest me how to do it
Here's a quick fix for the Subscripts:
Sub log_Script()
Dim cel As Range, rng As Range
Dim i&, k&
Dim myText$, findText$, curStr$
Set cel = Range("A1")
'myText = cel.Value
For i = 1 To Len(cel.Value)
k = k + 1
curStr = Mid(cel.Value, i, 1)
If curStr <> " " Then
findText = findText + curStr
ElseIf curStr = " " Then
findText = ""
End If
Debug.Print findText
If findText = "log" Then
If Mid(cel.Value, i + 1, 1) = " " Then
With cel.Characters(Start:=k + 2, Length:=1).Font
.Subscript = True
End With
Else
With cel.Characters(Start:=k + 1, Length:=1).Font
.Subscript = True
End With
End If
End If
Next i
End Sub
This will go through a range (set currently to be A1:A10), and for each cell, it'll look for log then take the next number and make it subscript. (Note: This is assuming all logs will have base < 10, let me know if that's not necessarily the case).
I could probably make this better, if you can post a few rows or cells from your CSV so I can see what the formatting is exacly like. (Or screenshot a part of your data, that 'd work too).
I have some code at the moment to draw a graph based on the values of a series of text boxes on an access form.
I’m happy with the code and how it works but I’m not convinced that it is the most efficient way of doing this. The graph takes about 1.2 seconds to redraw each time. The form is unbound so it is just getting the values from the text boxes. Just to check I got it to loop through and dump the text boxes values to debug.print and that did it instantly so it cant be that.
I suspect that it is trying to redraw the graph after each value is added. Is there a quicker way of doing this in VBA or am I stuck with it?
'**************************
'** Draw the Call Deviation graph **
'**************************
.cells(1, 1) = "Start Time"
.cells(1, 2) = "Deviation"
lRT_actual = 0
lRT_forecast = 0
For i = 1 To 48
lRT_actual = lRT_actual + Me.Controls("txtActual_" & i)
lRT_forecast = lRT_forecast + Me.Controls("txtForecast_" & i)
.cells(i + 1, 1) = Format(DateAdd("n", (i - 1) * 15, "08:00:00"), "HHMM")
.cells(i + 1, 2) = lRT_actual - lRT_forecast
If Me.acxProgress_bar.Value + 2 < 100 Then
Me.acxProgress_bar.Value = Me.acxProgress_bar.Value + 2
Else
Me.acxProgress_bar.Value = 90
End If
Next i
Thanks for your help
Would it be possible for you to add the values to a table and graph that?