如何解决透明绘制数千条线的最简单方法
我正在寻找最简单的方法来绘制多条线(〜20000条),既可以使用透明性支持,也可以使用子像素宽度或两者兼有,以使它们彼此叠置时不只是创建全黑图像。
我尝试过matplotlib,但是由于每一行都是它自己的轴,所以它很慢,尽管到目前为止看起来最好:
Option Explicit
Sub testRemoveDuplicateRows()
Const wsName As String = "Sheet1"
Const LastRowColumnID As Variant = "A" ' e.g. 1 or "A"
Const FirstRow As Long = 2
Dim ColumnIDs As Variant: ColumnIDs = Array(1,"M")
Dim wb As Workbook: Set wb = ThisWorkbook
Dim ws As Worksheet: Set ws = wb.Worksheets(wsName)
' Hide duplicate rows.
Call removeDuplicateRows(ws,ColumnIDs,LastRowColumnID,FirstRow,True)
' Delete duplicate rows.
'Call removeDuplicateRows(ws,FirstRow)
End Sub
Sub removeDuplicateRows(Sheet As Worksheet,_
ColumnIDs As Variant,_
Optional LastRowColumnID As Variant = 1,_
Optional FirstRow As Long = 1,_
Optional hideOnly As Boolean = False)
' Write values of columns to jagged array.
Dim Cols As Variant
Call getColumns(Cols,Sheet,FirstRow)
' Join values of arrays in jagged array.
Dim Data As Variant: Call joinColumns(Data,Cols)
' Write duplicate row numbers to array.
Dim RowOffset As Long: RowOffset = FirstRow - 1 ' 1 = ubound(Data)
Dim DupeRows As Variant
Call collectDuplicateRows(DupeRows,Data,RowOffset)
' Hide or delete duplicate rows.
If hideOnly Then
Call hideRows(Sheet,DupeRows)
Else
Call deleteRows(Sheet,DupeRows)
End If
End Sub
Sub getColumns(ByRef Data As Variant,_
Sheet As Worksheet,_
ColumnIDs As Variant,_
Optional LastRowColumnID As Variant = 1,_
Optional FirstRow As Long = 1)
Dim ubc As Long: ubc = UBound(ColumnIDs)
If ubc = -1 Then Exit Sub
Dim rng As Range: Call getColumnRange(rng,FirstRow)
If rng Is Nothing Then Exit Sub
ReDim Data(ubc): Call getColumnFromColumnRange(Data(0),rng)
If ubc > 0 Then GoSub getRemainingColumns
Exit Sub
getRemainingColumns:
Dim j As Long
For j = 1 To ubc
Call getColumnFromColumnRange(Data(j),_
rng.Offset(,Sheet.Columns(ColumnIDs(j)).Column - rng.Column))
Next j
Return
End Sub
Sub getColumnRange(ByRef ColumnRange As Range,_
Sheet As Worksheet,_
Optional ColumnID As Variant = 1,_
Optional FirstRow As Long = 1)
Set ColumnRange = Nothing
Dim rng As Range
Set rng = Sheet.Columns(ColumnID).Find("*",xlValues,xlPrevious)
If rng Is Nothing Then Exit Sub
If rng.Row < FirstRow Then Exit Sub
Set ColumnRange = Sheet.Range(Sheet.Cells(FirstRow,ColumnID),rng)
End Sub
Sub getColumnFromColumnRange(ByRef Data As Variant,_
ColumnRange As Range)
If ColumnRange Is Nothing Then Exit Sub
If ColumnRange.Cells.Count > 1 Then
Data = ColumnRange.Value
Else
ReDim Data(1 To 1,1 To 1): Data(1,1) = ColumnRange.Value
End If
End Sub
Sub joinColumns(ByRef Data As Variant,_
ColumnsArray As Variant,_
Optional Delimiter As String = "|||")
Data = ColumnsArray(0)
If UBound(ColumnsArray) = 0 Then Exit Sub
Dim ubr As Long: ubr = UBound(Data)
Dim j As Long,i As Long
For j = 1 To UBound(ColumnsArray)
For i = 1 To ubr
Data(i,1) = Data(i,1) & Delimiter & ColumnsArray(j)(i,1)
Next i
Next j
End Sub
Sub collectDuplicateRows(ByRef DupeRows As Variant,_
Data As Variant,_
Optional RowOffset As Long = 0,_
Optional DupeRowsFirstIndex As Long = 0)
Dim ub As Long: ub = UBound(Data)
If ub < 2 Then Exit Sub
Dim i As Long,k As Long,m As Long: m = DupeRowsFirstIndex - 1
ReDim DupeRows(DupeRowsFirstIndex To ub + DupeRowsFirstIndex - 2)
For i = 1 To ub - 1
For k = i + 1 To ub
If Data(k,1) Then
m = m + 1
DupeRows(m) = k + RowOffset
Exit For
End If
Next k
Next i
If m > DupeRowsFirstIndex - 1 Then
ReDim Preserve DupeRows(DupeRowsFirstIndex To m)
Else
DupeRows = Empty
End If
End Sub
Sub deleteRows(Sheet As Worksheet,_
RowNumbers As Variant)
Dim rng As Range: Set rng = Sheet.Rows(RowNumbers(LBound(RowNumbers)))
If UBound(RowNumbers) > LBound(RowNumbers) Then GoSub collectRemainingRows
If Not rng Is Nothing Then rng.EntireRow.Delete
Exit Sub
collectRemainingRows:
Dim j As Long
For j = LBound(RowNumbers) + 1 To UBound(RowNumbers)
Set rng = Union(rng,Sheet.Rows(RowNumbers(j)))
Next j
Return
End Sub
Sub hideRows(Sheet As Worksheet,_
RowNumbers As Variant)
Dim rng As Range: Set rng = Sheet.Rows(RowNumbers(LBound(RowNumbers)))
If UBound(RowNumbers) > LBound(RowNumbers) Then GoSub collectRemainingRows
If Not rng Is Nothing Then rng.EntireRow.Hidden = True
Exit Sub
collectRemainingRows:
Dim j As Long
For j = LBound(RowNumbers) + 1 To UBound(RowNumbers)
Set rng = Union(rng,Sheet.Rows(RowNumbers(j)))
Next j
Return
End Sub
有更快的方法吗?
我还尝试了使用PIL进行绘制,但是它不支持子像素线宽,并且alpha透明度只能应用于整个图像,而不能应用于单个元素:
import matplotlib.pyplot as plt
# test data in format my real data will use
test_data_as_lines = [((random()*2000,random()*2000),(random()*2000,random()*2000))
for x in range(0,20000)]
#format for matplotlib and plot
fig= plt.figure(figsize=(10,10))
axes= fig.add_axes([0.05,0.05,0.9,0.9])
for i in test_data_as_lines:
x = (i[0][0],i[1][0])
y = (i[0][1],i[1][1])
axes.plot(x,y,'black',linewidth=0.1,alpha=0.5)
plt.show()
这只是画一个黑色正方形。
最后,我尝试了John Zelle编写的简单graphics.py示例库,但这也不支持透明度或子像素宽度,甚至更慢。它基于tkinter,我认为它具有相同的局限性,所以我对此并不在意。
我试图避免pygame。那是我最好的选择吗?
谢谢
解决方法
摆脱for循环将使您的代码更简单,更快捷。由于方法plot
可以一次处理多行,因此可以使用
axes.plot(*test_data_as_lines,alpha=0.5,color="black",linewidth=0.1)
在我的笔记本电脑上,有5000行,使用for循环执行代码大约需要93秒,而上面的命令大约需要10秒
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。