Я построил графический движок в powershell для журналов IIS, размер точек масштабируется по количеству отображаемых точек (50-50k). когда размер маленький, легенда корректируется одновременно, поэтому я пытаюсь изменить размер маркера в легенде.
Я создал функцию события:
$chart1_CustomizeLegend = {
Param([Object]$sender , [System.Windows.Forms.DataVisualization.Charting.CustomizeLegendEventArgs]$e )
try
{
if ($e.LegendItems.Count -gt 0)
{
Write-Host found $e.LegendItems.Count legend items
for ($i = 0 ; $i -lt $e.LegendItems.Count ; $i++)
{
write-host processing $i
if ($e.LegendItems[$i] -eq $null)
{
write-host item is null
}
else
{
write-host item is not null
}
#update marker size
$e.LegendItems[$i].MarkerSize=10
}
}
} catch [System.Exception] {
Write-Error "failed to customize legend-item"
$_ | Format-List -Force | Out-String | Write-Error
}
}#CustomizeLegend
и зарегистрировал его:
$custjob = Register-ObjectEvent -InputObject $chart1 -EventName CustomizeLegend -Action $chart1_CustomizeLegend
и я вижу, что он вызывается, но он попадает в блок catch:
не удалось настроить элемент легенды
Исключение: System.NullReferenceException: объект
ссылка не установлена на экземпляр объекта.
в System.Windows.Forms.DataVisualization.Charting.Chart.Invalidate ()
в System.Windows.Forms.DataVisualization.Charting.ChartPicture.Invalidate ()
в System.Windows.Forms.DataVisualization.Charting.ChartElementCollection`1.Invalidate ()
в System.Windows.Forms.DataVisualization.Charting.ChartElement.Invalidate ()
в System.Windows.Forms.DataVisualization.Charting.Legend.Invalidate (Boolean
invalidateLegendOnly)
в CallSite.Target (Закрытие, CallSite, Object, Int32) TargetObject: CategoryInfo:
NotSpecified: (:) [], NullReferenceException FullyQualifiedErrorId:
ExceptionWhenSetting ErrorDetails: InvocationInfo:
System.Management.Automation.InvocationInfo ScriptStackTrace: at
, строка 763
в Write-IISResponseCharts, строка 906
at,: строка 1373 Информация о трубопроводе: {} PSMessageDetails:
но перед этим он пишет, что элемент не является нулевым, поэтому я знаю, что не делаю никаких исключений нулевой ссылки. Это похоже на проблему .NET, но ее очень сложно определить.
похоже, что это происходит во время SaveImage графика.
$ChartName = "IIS Response Time {0}-{1}, Series By Call Type, time-response scatter" -f $data.Folder,$data.File
Write-progress -status "Preparing $ChartName containing $($data.data.count) points" -activity "Preparing $ChartName, getting data"
$DataArray = $data.data |where {$_["time"]}| where $FilterSB | where $CoreFilterSB
$chart1 = New-object System.Windows.Forms.DataVisualization.Charting.Chart
$chart1.Width = 1200*$GraphScale
$chart1.Height = 800*$GraphScale
$chart1.BackColor = [System.Drawing.Color]::White
# title
$chart1.Titles.Add(("{0} ({1} of {2} points) " -f $ChartName, @($DataArray).Count, $data.data.count)) > $null
$chart1.Titles[0].Font = "Arial,{0}pt" -f (8*$GraphScale)
$chart1.Titles[0].Alignment = "topLeft"
# chart area
$chartarea = New-Object System.Windows.Forms.DataVisualization.Charting.ChartArea
$chartarea.Name = "ChartArea1"
$chartarea.AxisY.Title = "Response time (MS)"
$chartarea.AxisX.Title = "Time"
$chartarea.AxisY.LogarithmBase = 2
#$chartarea.axisy.IntervalAutoMode = [System.Windows.Forms.DataVisualization.Charting.IntervalAutoMode]::FixedCount
$chartarea.AxisX.Interval = 60
$chartarea.AxisX.IntervalType = [System.Windows.Forms.DataVisualization.Charting.DateTimeIntervalType]::Minutes
$chartarea.AxisX.LabelStyle.Font = "Arial,24pt"
$chartarea.AxisX.LabelStyle.Format="HH:mm"
#$chartarea.AxisX.Minimum = $StartTime.TotalMinutes
#$chartarea.AxisX.Maximum = $EndTime.TotalMinutes
#$chartarea.AxisX.Minimum = 0*60 #17:30
#$chartarea.AxisX.Maximum = 24.0*60 #20:00
$chartarea.AxisY.LabelStyle.Font = "Arial,24pt"
$chartarea.AxisY.Minimum = 256
if ($SetExceedingToMaxCallTime)
{
$chartarea.AxisY.Maximum = [Math]::Pow([Math]::Round([Math]::Sqrt($MaxCallTimeToChart)+0.5,0),2)*1024
}
else
{
$chartarea.AxisY.Maximum = 131072
}
$chartarea.AxisY.Interval = 1
$chartarea.AxisY.MinorGrid.Enabled = $true
$chartarea.AxisY.IsLogarithmic=$true
$chartarea.AxisY.MinorGrid.LineColor = [System.drawing.color]::LightGray
$chart1.ChartAreas.Add($chartarea)
# legend
if ($ShowLegend)
{
write-host add event to scatter chart
$custjob = Register-ObjectEvent -InputObject $chart1 -EventName CustomizeLegend -Action $chart1_CustomizeLegend
write-host 'create legend scatter chart'
$legend = New-Object system.Windows.Forms.DataVisualization.Charting.Legend
$legend.name = "Legend1"
$chart1.Legends.Add($legend)
write-host 'format legend scatter chart'
$chart1.Legends["Legend1"].Font = "Arial,{0}pt" -f (6 * $GraphScale)
$chart1.Legends["Legend1"].Docking =[System.Windows.Forms.DataVisualization.Charting.Docking]::Right
#$chart1.Legends["Legend1"].LegendItems
}
# data series
#$chart1.Series["wGLN"].Legend = "Legend1"
#$chart1.Series["wGLN"].color = "#62B5CC"
#dev
$labelNum = 0
$series = @()
$pointsadded = 0
$DataArray | ForEach-Object {
if ($pointsadded % 100 -eq 0) { write-host ("Adding data Series [{0}] Points [{1}]" -f $series.Count,$pointsadded) Write-progress -status ("Adding data Series [{0}] Points [{1}]" -f $series.Count,$pointsadded) -activity "Preparing $ChartName" }
$seriesname = Invoke-Command $seriesSB -ArgumentList $_
if (!($series -contains $seriesname))
{
write-host 'create a series'
$theSeries = $chart1.Series.Add($seriesname)
$theSeries.ChartType = "Point"
$theSeries.BorderWidth = 2
$theSeries.IsVisibleInLegend = $true
$theSeries.chartarea = "ChartArea1"
$theSeries.MarkerSize = 6/[Math]::Sqrt([Math]::Sqrt([Math]::Max($DataArray.Count/1000,1)))*$GraphScale
$theSeries.BorderColor=$theSeries.Color
$theSeries.BorderWidth = 2
write-host 'add series'
$series += $seriesname
$theSeries.IsVisibleInLegend=$true
$theseries.Legend = "Legend1"
}
else
{
#series dictionary is case sensitive however IIS logs are not,
#use whereclause instead of dictionary lookup to ensure case insensitive match!
$theSeries = $chart1.Series | where {$_.Name -eq $seriesname}
}
if ($_['time-taken'] -gt 0)
{
if ($SetExceedingToMaxCallTime)
{
$theSeries.Points.addxy( [DateTime]($_["time"]) , [Math]::Min($MaxCallTimeToChart*1000,($_['time-taken']))) > $null;
}
else
{
$theSeries.Points.addxy( [DateTime]($_["time"]) , (($_['time-taken']))) > $null;
}
}
$pointsadded++
}#each dataarray
foreach ($item in $chart1.Legends["Legend1"].CustomItems) {$item.MarkerSize = 8}
#$chart1.Show()
write-host "save charte $chartname"
$filename = "$DestinationPath\$ChartName.png"
$chart1.SaveImage($filename,"png")