Compare commits
No commits in common. "stock-composition" and "main" have entirely different histories.
stock-comp
...
main
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
julia_version = "1.11.4"
|
julia_version = "1.11.4"
|
||||||
manifest_format = "2.0"
|
manifest_format = "2.0"
|
||||||
project_hash = "ec502e8d73a739a6239b751344af945fa59e7806"
|
project_hash = "0a18a0873213e0e8660a5eb202a1fa9f1621a652"
|
||||||
|
|
||||||
[[deps.AbstractFFTs]]
|
[[deps.AbstractFFTs]]
|
||||||
deps = ["LinearAlgebra"]
|
deps = ["LinearAlgebra"]
|
||||||
|
|
|
@ -7,12 +7,10 @@ version = "0.1.0"
|
||||||
FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
|
FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
|
||||||
Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0"
|
Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0"
|
||||||
Luxor = "ae8d54c2-7ccd-5906-9d76-62fc9837b5bc"
|
Luxor = "ae8d54c2-7ccd-5906-9d76-62fc9837b5bc"
|
||||||
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
|
|
||||||
VideoIO = "d6d074c3-1acf-5d4c-9a43-ef38773959a2"
|
VideoIO = "d6d074c3-1acf-5d4c-9a43-ef38773959a2"
|
||||||
|
|
||||||
[compat]
|
[compat]
|
||||||
FileIO = "1.17.0"
|
FileIO = "1.17.0"
|
||||||
Images = "0.26.2"
|
Images = "0.26.2"
|
||||||
Luxor = "4.2.0"
|
Luxor = "4.2.0"
|
||||||
Statistics = "1.11.1"
|
|
||||||
VideoIO = "1.1.1"
|
VideoIO = "1.1.1"
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
using Images
|
|
||||||
|
|
||||||
"""
|
|
||||||
Converts image to grayscale
|
|
||||||
"""
|
|
||||||
function greyscale(c::Images.RGB)::Real
|
|
||||||
return Real(c.r)
|
|
||||||
end
|
|
|
@ -1,103 +0,0 @@
|
||||||
using Base
|
|
||||||
import Luxor as L
|
|
||||||
|
|
||||||
"""
|
|
||||||
Colour of a component given its fluctuations
|
|
||||||
"""
|
|
||||||
function colour_of_diff(diff::Real)::Tuple{Real,Real,Real}
|
|
||||||
if diff > 0
|
|
||||||
return (0.5,1,0.5)
|
|
||||||
else
|
|
||||||
return (1,0.5,0.5)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
component_text_size = 20
|
|
||||||
|
|
||||||
@kwdef struct Component
|
|
||||||
pos::Tuple{UInt, UInt}
|
|
||||||
size::Tuple{UInt, UInt}
|
|
||||||
name::String
|
|
||||||
diff::Real
|
|
||||||
end
|
|
||||||
|
|
||||||
sector_title_font_size = 16
|
|
||||||
sector_title_height = 20
|
|
||||||
|
|
||||||
@kwdef struct Sector
|
|
||||||
name::String
|
|
||||||
pos::Tuple{UInt, UInt}
|
|
||||||
size::Tuple{UInt, UInt}
|
|
||||||
components::Array{Component}
|
|
||||||
end
|
|
||||||
|
|
||||||
@kwdef struct CompositionDiagram
|
|
||||||
sectors::Array{Sector}
|
|
||||||
end
|
|
||||||
|
|
||||||
"""
|
|
||||||
Draws stock index composition chart
|
|
||||||
"""
|
|
||||||
function draw(diagram::CompositionDiagram, size=(800, 600))
|
|
||||||
L.Drawing(size[1], size[2], :png)
|
|
||||||
L.background("black")
|
|
||||||
for sector in diagram.sectors
|
|
||||||
L.sethue("gray")
|
|
||||||
L.rect(L.Point(sector.pos), sector.size[1], sector.size[2], action = :fillpreserve)
|
|
||||||
L.setline(2)
|
|
||||||
L.strokepath()
|
|
||||||
L.sethue("white")
|
|
||||||
L.setfont("Helvetica", sector_title_font_size)
|
|
||||||
L.settext(
|
|
||||||
sector.name,
|
|
||||||
L.Point(sector.pos),
|
|
||||||
halign="left",
|
|
||||||
valign="top",
|
|
||||||
)
|
|
||||||
L.setfont("Helvetica", component_text_size)
|
|
||||||
for component in sector.components
|
|
||||||
pos = sector.pos .+ component.pos
|
|
||||||
L.setcolor(colour_of_diff(component.diff))
|
|
||||||
L.rect(L.Point(pos), component.size[1], component.size[2], action = :fillpreserve)
|
|
||||||
L.sethue("white")
|
|
||||||
L.setline(5)
|
|
||||||
L.strokepath()
|
|
||||||
L.settext(
|
|
||||||
component.name,
|
|
||||||
L.Point(pos .+ component.size ./ 2),
|
|
||||||
halign="center",
|
|
||||||
valign="bottom",
|
|
||||||
)
|
|
||||||
L.settext(
|
|
||||||
"$(component.diff)%",
|
|
||||||
L.Point(pos .+ component.size ./ 2),
|
|
||||||
halign="center",
|
|
||||||
valign="top",
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
L.finish()
|
|
||||||
end
|
|
||||||
|
|
||||||
diagram = CompositionDiagram(
|
|
||||||
sectors=[
|
|
||||||
Sector(
|
|
||||||
name="technology",
|
|
||||||
pos=(0,0),
|
|
||||||
size=(200,300),
|
|
||||||
components=[
|
|
||||||
Component(pos=(0,20), size=(200,200),name="AAPL", diff=0.5),
|
|
||||||
Component(pos=(0,200), size=(200,100),name="GOOG", diff=-0.3),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Sector(
|
|
||||||
name="resources",
|
|
||||||
pos=(200,0),
|
|
||||||
size=(200,200),
|
|
||||||
components=[
|
|
||||||
Component(pos=(0,20), size=(200,150),name="OIL", diff=0.1),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
draw(diagram)
|
|
132
src/tdpacking.jl
132
src/tdpacking.jl
|
@ -1,132 +0,0 @@
|
||||||
using Base
|
|
||||||
using Statistics, Images
|
|
||||||
import Luxor as L
|
|
||||||
|
|
||||||
@kwdef struct Region
|
|
||||||
pos::Tuple{Int,Int}
|
|
||||||
size::Tuple{Int,Int}
|
|
||||||
# If true, this region increases from x to y. This direction variable steers
|
|
||||||
# the direction of cut.
|
|
||||||
dir::Bool
|
|
||||||
end
|
|
||||||
|
|
||||||
# Time-dependent packing
|
|
||||||
@kwdef struct Rect
|
|
||||||
pos::Tuple{Int,Int}
|
|
||||||
size::Tuple{Int,Int}
|
|
||||||
color::Real
|
|
||||||
end
|
|
||||||
|
|
||||||
function area(r::Rect)::Int
|
|
||||||
return r.size[1] * r.size[2]
|
|
||||||
end
|
|
||||||
function aspect_ratio(r::Rect)::Real
|
|
||||||
return r.size[1] / r.size[2]
|
|
||||||
end
|
|
||||||
|
|
||||||
"""
|
|
||||||
divide_image(img::Matrix{}, size_min::Int=16, size_max::Int=256)
|
|
||||||
|
|
||||||
Divides an image into rectangles of the same colour. The rectangles are not
|
|
||||||
allowed to have extreme aspect ratios. There is a minimal size of each retangle.
|
|
||||||
"""
|
|
||||||
function divide_image(img::Matrix{}; size_min::Int=16, size_max::Int=128, threshold_aspect::Real=3.0, threshold_std::Real=0.4)::Array{Rect}
|
|
||||||
remainder = [Region(pos=(1,1), size=size(img), dir=false)]
|
|
||||||
result = Rect[]
|
|
||||||
|
|
||||||
# Loop until the entire field is filled
|
|
||||||
while length(remainder) > 0
|
|
||||||
section = pop!(remainder)
|
|
||||||
|
|
||||||
(px, py) = section.pos
|
|
||||||
(sx, sy) = section.size
|
|
||||||
|
|
||||||
@assert px + sx - 1 <= size(img)[1]
|
|
||||||
@assert py + sy - 1 <= size(img)[2]
|
|
||||||
|
|
||||||
width = 1
|
|
||||||
height = 1
|
|
||||||
|
|
||||||
width_max = min(sx, size_max)
|
|
||||||
height_max = min(sy, size_max)
|
|
||||||
|
|
||||||
# Try to expand this rectangle to the maximum size
|
|
||||||
|
|
||||||
while width < width_max || height < height_max
|
|
||||||
subimg = img[px:px+width-1, py:py+height-1]
|
|
||||||
if std(subimg) >= threshold_std
|
|
||||||
break
|
|
||||||
end
|
|
||||||
colour = mean(subimg)
|
|
||||||
ar = width / height
|
|
||||||
|
|
||||||
if width < width_max && ar < threshold_aspect
|
|
||||||
width += 1
|
|
||||||
elseif height < height_max && ar > 1/threshold_aspect
|
|
||||||
height += 1
|
|
||||||
else
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@assert width <= sx
|
|
||||||
@assert height <= sy
|
|
||||||
|
|
||||||
subimg = img[px:px+width-1, py:py+height-1]
|
|
||||||
rect = Rect(
|
|
||||||
pos=section.pos,
|
|
||||||
size=(width, height),
|
|
||||||
color=mean(subimg),
|
|
||||||
)
|
|
||||||
push!(result, rect)
|
|
||||||
|
|
||||||
if section.dir
|
|
||||||
if width < sx
|
|
||||||
push!(remainder, Region(
|
|
||||||
pos=(px + width, py),
|
|
||||||
size=(sx - width, height),
|
|
||||||
dir=false,
|
|
||||||
))
|
|
||||||
end
|
|
||||||
if height < sy
|
|
||||||
push!(remainder, Region(
|
|
||||||
pos=(px, py + height),
|
|
||||||
size=(sx, sy - height),
|
|
||||||
dir=true,
|
|
||||||
))
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if height < sy
|
|
||||||
push!(remainder, Region(
|
|
||||||
pos=(px, py + height),
|
|
||||||
size=(width, sy - height),
|
|
||||||
dir=true,
|
|
||||||
))
|
|
||||||
end
|
|
||||||
if width < sx
|
|
||||||
push!(remainder, Region(
|
|
||||||
pos=(px + width, py),
|
|
||||||
size=(sx - width, sy),
|
|
||||||
dir=false,
|
|
||||||
))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return result
|
|
||||||
end
|
|
||||||
|
|
||||||
"""
|
|
||||||
draw_rect(size::Tuple{Int, Int}, rects::Array{Rect})
|
|
||||||
|
|
||||||
Displays the divided image in greyscale.
|
|
||||||
"""
|
|
||||||
function draw_rect(size::Tuple{Int, Int}, rects::Array{Rect})
|
|
||||||
L.Drawing(size[1], size[2], :png)
|
|
||||||
L.background("black")
|
|
||||||
for rect in rects
|
|
||||||
c = N0f8(rect.color)
|
|
||||||
setcolor(c, c, c)
|
|
||||||
L.rect(L.Point(rect.pos), rect.size[1], rect.size[2], action = :fill)
|
|
||||||
end
|
|
||||||
L.finish()
|
|
||||||
end
|
|
Loading…
Reference in New Issue