前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >BeautifulMakie绝对是一个Julia的宝藏级可视化库

BeautifulMakie绝对是一个Julia的宝藏级可视化库

作者头像
郭好奇同学
发布2022-04-15 16:04:05
7940
发布2022-04-15 16:04:05
举报
文章被收录于专栏:好奇心Log好奇心Log

全球地震3D分布图(静态)

暗黑系列宇宙图(静态)

地形图(静态)

偶然间看到一款适用于地球科学领域可视化的Julia库,深深地被少量的代码和酷炫的3D可视化效果所震撼,在这里与大家一同分享。从下面的gallery不难看出,无论是视频动态图、曲线图、等值线图、以及一些统计相关的图都是气象所常用的科学图片类型,我们之前介绍过Julia的很多内容,大多是关于基础、发展情况、算法等等,相对全面的可视化库介绍的比较少。

本文展示的可能只有十分之一不到,大家可以自行到官网查看并且使用,都是开源免费的。不多废话直接上链接:https://lazarusa.github.io/BeautifulMakie/

地震3D的代码:

代码语言:javascript
复制
#by Lazaro Alonso
using CSV, DataFrames
using GLMakie
using FileIO, Downloads

let
    earth_img = load(Downloads.download("https://upload.wikimedia.org/wikipedia/commons/9/96/NASA_bathymetric_world_map.jpg"))
    function sphere(; r = 1.0, n = 32)
        θ = LinRange(0, π, n)
        φ = LinRange(-π, π, 2 * n)
        x = [r * cos(φ) * sin(θ) for θ in θ, φ in φ]
        y = [r * sin(φ) * sin(θ) for θ in θ, φ in φ]
        z = [r * cos(θ) for θ in θ, φ in φ]
        return (x, y, z)
    end

    # https://earthquake.usgs.gov/earthquakes/map/?extent=-68.39918,-248.90625&extent=72.60712,110.74219
    file1 = Downloads.download("https://github.com/lazarusA/BeautifulMakie/raw/main/_assets/data/2021_01_2021_05.csv")
    file2 = Downloads.download("https://github.com/lazarusA/BeautifulMakie/raw/main/_assets/data/2021_06_2022_01.csv")
    earthquakes1 = DataFrame(CSV.File(file1))
    earthquakes2 = DataFrame(CSV.File(file2))
    earthquakes = vcat(earthquakes1, earthquakes2)

    # depth unit, km
    function toCartesian(lon, lat; r = 1.02, cxyz = (0, 0, 0))
        x = cxyz[1] + (r + 1000_000) * cosd(lat) * cosd(lon)
        y = cxyz[2] + (r + 1000_000) * cosd(lat) * sind(lon)
        z = cxyz[3] + (r + 1000_000) * sind(lat)
        return (x, y, z) ./ 1000_000
    end

    lons, lats = earthquakes.longitude, earthquakes.latitude
    depth = earthquakes.depth
    toPoints3D = [Point3f([toCartesian(lons[i], lats[i]; r = -depth[i] * 1000)...]) for i in 1:length(lons)]

    ms = (exp.(earthquakes.mag) .- minimum(exp.(earthquakes.mag))) ./ maximum(exp.(earthquakes.mag) .- minimum(exp.(earthquakes.mag)))

    set_theme!(theme_black())
    fig = Figure(resolution = (1400, 1400), fontsize = 24)
    ax = LScene(fig[1, 1], show_axis = false)
    pltobj = meshscatter!(ax, toPoints3D; markersize = ms / 20 .+ 0.001,
        color = earthquakes.mag,
        colormap = to_colormap(:afmhot)[10:end],
        shading = true,
        ambient = Vec3f(0.99, 0.99, 0.99))
    surface!(ax, sphere(; r = 1.0)..., color = tuple.(earth_img, 0.1), shading = true,
        transparency = true)
    Colorbar(fig[1, 2], pltobj, label = "Magnitude",
        height = Relative(1.5 / 4))
    Label(fig[1, 1, Bottom()], "Visualization by @LazarusAlon\nusing Makie")
    Label(fig[1, 1, Top()], "Earthquakes on Earth between January 2021 and January 2022.\nOriginal data from USGS")
    zoom!(ax.scene, cameracontrols(ax.scene), 0.65)
    rotate!(ax.scene, 3.0)
    fig
    save("earthquakes.png", fig, px_per_unit = 2.0)

    record(fig, joinpath(@__DIR__, "output", "earthquakes.mp4"), framerate = 24) do io
        for i in 3.0:0.015:9
            rotate!(ax.scene, i)
            recordframe!(io)  # record a new frame
        end
    end
end

出图效果:

暗黑主题宇宙图代码:

代码语言:javascript
复制
# by lazarusA & Julius Krumbiegel
using Makie, CairoMakie, HTTP, CSV, DataFrames, DataFramesMeta, Suppressor
using Images, ColorSchemes, Colors, Statistics
using Lazy: @>
CairoMakie.activate!()
let
    data_url = "https://bit.ly/3kmlGn2"
    @suppress begin
        global astronauts
        astronauts = CSV.File(HTTP.download(data_url)) |> DataFrame
    end
    offhr, rPts, α = 3.5, 45, 35
    astro = @> begin
        astronauts
        @orderby(:year_of_mission)
        @where(:total_eva_hrs .> 0.0)
        @transform(ntotEVA = :total_eva_hrs/ maximum(:total_eva_hrs))
        @transform(θ = LinRange(0, 2π - 2π/length(:name), length(:name)))
        @transform(align = tuple.(ifelse.(π/2 .< :θ .< 3π/2, ^(:right), ^(:left)), ^(:center)))
        @transform(texttheta = ifelse.(π/2 .< :θ .< 3π/2, :θ .+ π, :θ))
        @transform(evaM = log10.((60 * :eva_hrs_mission/median(60 * :eva_hrs_mission)) .+ offhr))
        @transform(xM = rPts * :evaM .* cos.(:θ), yM = rPts * :evaM .* sin.(:θ))
        @transform(xMnm = rPts * (:evaM .- :total_number_of_missions .* :evaM./α) .* cos.(:θ))
        @transform(yMnm = rPts * (:evaM .- :total_number_of_missions .* :evaM./α) .* sin.(:θ))
    end
    valYear = @> begin astro
            @where([true; :year_of_mission[2:end] .!= :year_of_mission[1:end-1]])
        end
    vehicles = @> begin astro
            @where([true; :ascend_shuttle[2:end] .!= :ascend_shuttle[1:end-1]])
        end
    tierra = "https://climate.nasa.gov/system/internal_resources/details/original/309_ImageWall5_768px-60.jpg"
    @suppress begin
        global imgEarth
        tierra = HTTP.download(tierra)
        imgEarth = load(tierra)
    end
    function getPoints(xi,yi,xf,yf)
        xyos = []
        for i in 1:length(xo)
            push!(xyos, [xi[i], yi[i]])
            push!(xyos, [xf[i], yf[i]])
        end
        xyos
    end
    x, y = astro.xM, astro.yM # end points
    xs, ys = astro.xMnm, astro.yMnm # short lines starts
    xo = yo = zeros(length(x)) # origin
    xnb, ynb = 90 * cos.(astro.θ), 90 * sin.(astro.θ)
    xne, yne = 100 * cos.(astro.θ), 100 * sin.(astro.θ)
    ps, colorp = 0.5 .+ 3astro.ntotEVA, astro.total_eva_hrs ; # point size, color palette
    gridLines = LinRange(log10(offhr), maximum(astro.evaM), 6)
    horas = (10 .^ gridLines .- offhr)*median(60*astro.eva_hrs_mission)/60
    xg = [rPts * gl .* cos.(astro.θ) for gl in gridLines]
    yg = [rPts * gl .* sin.(astro.θ) for gl in gridLines]
    # in order to use linesegments (faster to plot)
    xyos = getPoints(xo,yo,xs,ys)
    xys  = getPoints(xs,ys,x,y)
    xybe = getPoints(xnb,ynb,xne,yne)
    cpDo = repeat(colorp, inner=2)
    psDo = repeat(ps, inner=2);

    with_theme(theme_black()) do
        fig = Figure(resolution = (1200, 1200))
        cmap = :rainbow2
        ax = CairoMakie.Axis(fig[1, 1],
            title = "ASTRONAUTS' EXTRAVEHICULAR ACTIVITIES",
            autolimitaspect = 1)
        hidespines!(ax)
        hidedecorations!(ax)
        image!(-20..20, -17..17, rotr90(imgEarth))
        text!(astro.name, position = @.(Point(cos(astro.θ), sin(astro.θ)) * 85),
            rotation = astro.texttheta, textsize = 6, align = astro.align)
        text!(string.(valYear.year_of_mission),
            position = @.(Point(cos(valYear.θ), sin(valYear.θ)) * 65),
            rotation = valYear.texttheta, textsize = 10, align = valYear.align)
        text!(vehicles.ascend_shuttle,
            position = @.(Point(cos(vehicles.θ), sin(vehicles.θ)) * 73),
            rotation = vehicles.texttheta, textsize = 6, align = vehicles.align)

        pltobj = scatter!(ax, astro[:,:xM], astro[:,:yM], color = colorp,
            colormap = cmap, markersize = 3*ps, strokewidth = 0)

        linesegments!(Point2f0.(xyos), color = cpDo, linewidth = psDo/2, colormap = (cmap, 0.15))
        linesegments!(Point2f0.(xys), color = cpDo, linewidth = psDo/2,colormap = cmap)
        linesegments!(Point2f0.(xybe), color = cpDo, linewidth = psDo/3, colormap = (cmap,0.5))

        Colorbar(fig[1,1], pltobj,
            label = "Total duration of all extravehicular activities in hours",
            tellheight = false, tellwidth = false, ticklabelsize = 12, flipaxis = true,
            vertical = false, ticksize=15, tickalign = 1, width = Relative(1.5/4),
            halign = :right, valign = :bottom, labelsize = 12)

        for (indx, gl) in enumerate(gridLines)
            xg, yg = rPts * gl .* cos.(astro.θ), rPts * gl .* sin.(astro.θ)
            hrs = Int64(round(horas[indx], digits = 0))
            lines!(xg, yg, linewidth = 0.5, linestyle = :dash, color = :white)
            text!(string.(hrs), position = (xg[1] + 0.5, y[1]+0.5),
                color = "#FFDD33", textsize = 14)
        end
        lines!([rPts*gridLines[1], rPts*gridLines[end]],[0,0],linestyle = :dash,
            linewidth = 2, color =  "#FFDD33")
        text!("evaM (hrs)", position = (47, -3.5), color = "#FFDD33", textsize = 16)
        text!("evaM ≡ Duration of extravehicular \n activities during the mission in hours",
            position = (rPts*gridLines[end-2], 90), color = "#FFDD33", textsize = 16)
        text!("using Makie", position = (-99, -94), textsize = 18, color = :white)
        text!("Visualization by @LazarusAlon and Julius Krumbiegel ",
            position = (-99, -97), textsize = 12, color = "#61AFEF")
        text!("Data - Astronaut Database - Mariya Stavnichuk and Tatsuya Corlett",
            position = (-99, -99), textsize = 10)
        limits!(ax, -100, 100, -100, 100)
    end

end

出图效果:

富士山地形图代码:

代码语言:javascript
复制
using GLMakie, ArchGDAL
let
    dataset = ArchGDAL.read("./data/fuji.tif")
    # just in case you want to know more about the file structure
    #ArchGDAL.read("fuji.tif") do ds
    #    println(ArchGDAL.gdalinfo(ds))
    #end
    dataset_read = ArchGDAL.read(dataset)
    topo = dataset_read[:,end:-1:1];

    fig, ax, pltobj = lines(topo[561,50:end-30], linewidth = 0.85,
        figure = (resolution = (800,1000),backgroundcolor = :black,),
        axis = (backgroundcolor = :black,))
    c = 560
    for i in 1:1:560
        lines!(ax, topo[i,50:end-30] .+ 15*c, linewidth = 0.85, overdraw = true,
            colorrange = (minimum(topo), maximum(topo)),
            color = topo[i,50:end-30], colormap = :turbo) # :linear_bmy_10_95_c78_n256
        c -= 1
    end
    text!(ax,"Fuji", position = (250, 0),color = :white, textsize = 24)
    text!(ax,"Visualization by",position=(0, -20),color = :white,textsize = 12)
    text!(ax,"@LazarusAlon", position = (0, -200),color = :white,textsize = 12)
    hidedecorations!(ax)
    hidespines!(ax)
    hidedecorations!(ax)
    hidespines!(ax)
    fig
end

出图效果:

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-04-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 好奇心Log 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
图像处理
图像处理基于腾讯云深度学习等人工智能技术,提供综合性的图像优化处理服务,包括图像质量评估、图像清晰度增强、图像智能裁剪等。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档