当前位置: 首页 > news >正文

PowerBI实战-制作带有同比及趋势线的双柱状图

一、引言

今天的PowerBI报表的制作相对有一点复杂,我们直接根据最终展示图来讲解:

可以看到,我们今天要制作的图像需要包括以下几点:时间维度的趋势、两种不同维度的数据对比、不同数据标签的展示、不同年份间环比的标签展示以及上方趋势线以及趋势标签的制作。

最终清晰展现交互性的时间趋势环比双柱状图。

二、具体教学

那么该如何制作这样一张表呢?

我们的基础数据源需要用到三列数据:

【日期列】(图中年份数据)、【双柱状图数据】(图中浅蓝色为中国部分的数据,橙色为Global部分数据)

首先我们需要用到的可视化对象:

接着我们需要构建在两个基础度量值,分别计算当前计算到的中国部分数据总和以及Global部分数据总和:

Current_year_CNPVO_value = sum('PVO&CNI_BI'[Total CHN PVO])

Current_year_GlobalPVO_value = sum('PVO&CNI_BI'[Global PVO])

接着我们绘制我们的双柱状图的代码:

Bar_PVO =
// 'PVO&CNI_BI'[YEAR] ), [000 Current_year_CNPVO_value], [000 Current_year_GlobalPVO_value]

VAR Width_Bar =80 //每个柱形空间宽度

VAR Width_BarAct =35 //每个柱形实际宽度(减小宽度以容纳两个柱子)

VAR GapBetweenBars = 3 //两个柱子之间的间距

VAR Height_ItemLabel = 20 //类别标签高度

VAR Height_Bar = 200 //柱形最大高度

VAR FontSize = 14 //字号

VAR SpaceAboveRect = 100 //柱形上方留一定空间

VAR Height_Total = Height_ItemLabel + Height_Bar + SpaceAboveRect

VAR MaxValueCN = MAXX( ALLSELECTED( 'PVO&CNI_BI'[YEAR] ), [000 Current_year_CNPVO_value] )

VAR MaxValueGlobal = MAXX( ALLSELECTED( 'PVO&CNI_BI'[YEAR] ), [000 Current_year_GlobalPVO_value] )

VAR MaxValue = MAX(MaxValueCN, MaxValueGlobal) //取两个指标的最大值

VAR Chart ="

        <!-- CN PVO 柱子 -->

        <rect

                x='" & (Width_Bar - (Width_BarAct * 2 + GapBetweenBars)) / 2 & "'

                y='" & Height_Total - Height_ItemLabel - Height_Bar * [000 Current_year_CNPVO_value] /                 MaxValue & "'

                height='" & Height_Bar * [000 Current_year_CNPVO_value] / MaxValue & "'

                width='" & Width_BarAct & "'

                fill='lightblue' />

        <!-- Global PVO 柱子 -->

        <rect

                x='" & (Width_Bar - (Width_BarAct * 2 + GapBetweenBars)) / 2 + Width_BarAct + GapBetweenBars & "'

                y='" & Height_Total - Height_ItemLabel - Height_Bar * [000 Current_year_GlobalPVO_value] / MaxValue & "'

                height='" & Height_Bar * [000 Current_year_GlobalPVO_value] / MaxValue & "'

                width='" & Width_BarAct & "'

                fill='orange' />

        <!-- 数值标签 -->

        <text

                x='" & (Width_Bar - (Width_BarAct * 2 + GapBetweenBars)) / 2 + Width_BarAct / 2 & "'

                y='" & Height_Total - Height_ItemLabel - Height_Bar * [000 Current_year_CNPVO_value] /                 MaxValue - 5 & "' text-anchor='middle'

                font-size='" & FontSize * 0.7 & "'

                fill='deepskyblue'

        >" & "</text>

        <text

                x='" & (Width_Bar - (Width_BarAct * 2 + GapBetweenBars)) / 2 + Width_BarAct * 1.5 + GapBetweenBars & "'

                y='" & Height_Total - Height_ItemLabel - Height_Bar * [000 Current_year_GlobalPVO_value] / MaxValue - 5 & "'

                text-anchor='middle'

                font-size='" & FontSize * 0.7 & "'

                fill='orange'

>" & "</text>

        <!-- 年份标签 -->

        <text

                x='" & Width_Bar / 2 & "' y='" & Height_Total - FontSize / 2 & "' text-anchor='middle'

                dominant-baseline='middle'

                font-size='" & FontSize & "'

                font-weight='bold' >" & SELECTEDVALUE('PVO&CNI_BI'[YEAR]) & "</text>"

RETURN

        "<svg xmlns='http://www.w3.org/2000/svg' id='" &         SELECTEDVALUE('PVO&CNI_BI'[YEAR]) & "'

        width='" & Width_Bar & "'

        height='" & Height_Total & "'>"

        & Chart & "

</svg>"

然后是将对应数据与上面绘制的图像相结合:

Stylesheet = 
// 'PVO&CNI_BI'[YEAR] ), [000 Current_year_CNPVO_value], [000 Current_year_GlobalPVO_value]
VAR n = COUNTROWS( ALLSELECTED( 'PVO&CNI_BI'[YEAR] ))
VAR Width_Bar = 80 //每个柱形空间宽度
VAR Width_BarAct_CNPVO = 35 //CNPVO柱形实际宽度
VAR Width_BarAct_Global = 21 //GlobalPVO柱形实际宽度(CNPVO宽度的60%)
VAR Width_Total = Width_Bar * n
VAR Height_ItemLabel = 20 //类别标签高度
VAR Height_Bar = 200 //柱形最大高度
VAR FontSize = 12 //字号
VAR SpaceAboveRect = 100 //柱形上方留一定空间
 

// 分别计算CNPVO和GlobalPVO的最大值
VAR MaxValue_CNPVO =
    MAXX ( ALLSELECTED ( 'PVO&CNI_BI'[YEAR] ), [000 Current_year_CNPVO_value] )
VAR MaxValue_GlobalPVO =
    MAXX ( ALLSELECTED ( 'PVO&CNI_BI'[YEAR] ), [000 Current_year_GlobalPVO_value] )

// 分别计算CNPVO和GlobalPVO的总高度
VAR Height_Total_CNPVO = Height_ItemLabel + Height_Bar + SpaceAboveRect
VAR Height_Total_Global = Height_ItemLabel + Height_Bar + SpaceAboveRect

// 修正FirstValue和LastValue的计算
VAR FirstValue =
    CALCULATE(
        [000 Current_year_CNPVO_value],
        TOPN(1, ALLSELECTED('PVO&CNI_BI'[YEAR]), 'PVO&CNI_BI'[YEAR], ASC)
    )
VAR LastValue =
    CALCULATE(
        [000 Current_year_CNPVO_value],
        TOPN(1, ALLSELECTED('PVO&CNI_BI'[YEAR]), 'PVO&CNI_BI'[YEAR], DESC)
    )
VAR Gap = DIVIDE(LastValue-FirstValue,FirstValue)
 

// 获取第一个和最后一个柱子的中心X坐标
VAR FirstBarCenterX = Width_Bar / 4          // 调整gap线的首端位置
VAR LastBarCenterX = Width_Total - Width_Bar*(3/4) // 调整gap线的尾端位置
 

// 创建横向排列的柱形
VAR HorizontalBars = 
CONCATENATEX(
    ALLSELECTED('PVO&CNI_BI'[YEAR]),
    VAR CurrentValue = [000 Current_year_CNPVO_value]
    VAR GlobalValue = [000 Current_year_GlobalPVO_value]
    
    // 分别计算CNPVO和GlobalPVO的柱子高度
    VAR CNPVO_BarHeight = Height_Bar * CurrentValue / MaxValue_CNPVO
    VAR Global_BarHeight = Height_Bar * GlobalValue / MaxValue_GlobalPVO
    
    // 分别计算CNPVO和GlobalPVO的柱子Y位置
    VAR CNPVO_PositionY = Height_Total_CNPVO - Height_ItemLabel - CNPVO_BarHeight
    VAR Global_PositionY = Height_Total_Global - Height_ItemLabel - Global_BarHeight
    
    VAR PositionX = (RANKX(ALLSELECTED('PVO&CNI_BI'[YEAR]), 'PVO&CNI_BI'[YEAR],,ASC) - 1) * Width_Bar

    
    // 分别计算CNPVO和GlobalPVO的X位置
    VAR CNPVO_PositionX = PositionX + (Width_Bar - Width_BarAct_CNPVO) / 2
    VAR Global_PositionX = PositionX + (Width_Bar - Width_BarAct_Global) / (1.2)
    
    VAR YearValue = SELECTEDVALUE('PVO&CNI_BI'[YEAR])
    
    // 分别计算CNPVO和GlobalPVO柱子中心X坐标
    VAR CNPVO_BarCenterX = CNPVO_PositionX + Width_BarAct_CNPVO / 2
    VAR Global_BarCenterX = Global_PositionX + Width_BarAct_Global / 2
    
    // 计算百分比标签的X坐标
    VAR MonthIndex = RANKX(ALLSELECTED('PVO&CNI_BI'[YEAR]), 'PVO&CNI_BI'[YEAR],,ASC)
    VAR PercentPositionX = (MonthIndex - 1) * Width_Bar + (Width_Bar - Width_BarAct_CNPVO) / 5.5
    VAR PercentBarCenterX = PercentPositionX + Width_BarAct_CNPVO / 4
    
    // 计算百分比标签的Y坐标,并向上移动10个单位
    VAR PercentBarHeight = Height_Bar * CurrentValue / MaxValue_CNPVO * 0.3
    VAR PercentPositionY = Height_Total_CNPVO - Height_ItemLabel - PercentBarHeight - 45 - 10
    
    // 计算CNPVO数值标签的Y坐标,位于百分比标签下方
    VAR CNPVO_ValueLabelY = PercentPositionY + 20


RETURN
    // CNPVO柱形
    "<rect x='" & CNPVO_PositionX & "' y='" & CNPVO_PositionY & 
    "' width='" & Width_BarAct_CNPVO & "' height='" & CNPVO_BarHeight & 
    "' fill='transparent' rx='2'/>" &
    
    // GlobalPVO柱形
    "<rect x='" & Global_PositionX & "' y='" & Global_PositionY & 
    "' width='" & Width_BarAct_Global & "' height='" & Global_BarHeight & 
    "' fill='transparent' opacity='0.6' rx='2'/>" &
    
    // 年份标签
    "<text x='" & CNPVO_BarCenterX & "' y='" & (Height_Total_CNPVO - 5) & 
    "' text-anchor='middle' font-size='" & FontSize * 0.8 & "'>" & YearValue & "</text>" &
    
    // CNPVO数值标签
    "<text x='" & PercentBarCenterX & "' y='" & CNPVO_ValueLabelY &
    "' text-anchor='middle' font-size='" & FontSize * 0.8 & "'>" & FORMAT(CurrentValue, "#,##0.0") & "</text>" &
    
    // GlobalPVO数值标签(使用Global柱子的中心X坐标)
    "<text x='" & Global_BarCenterX & "' y='" & (Global_PositionY - 5) &
    "' text-anchor='middle' font-size='" & FontSize * 0.7 & "' fill='black'>" & FORMAT(GlobalValue, "#,##0.0") & "</text>"
)


// LineBtw保持不变(百分比标签的位置计算),但需要向上移动10个单位
VAR LineBtw = ADDCOLUMNS(ALLSELECTED('PVO&CNI_BI'[YEAR]),"line",
VAR CurrentYear = SELECTEDVALUE('PVO&CNI_BI'[YEAR])
VAR PreviousYearIndex = RANKX(ALLSELECTED('PVO&CNI_BI'[YEAR]), 'PVO&CNI_BI'[YEAR],,ASC) - 1
VAR PreviousValue = 
    IF(PreviousYearIndex >= 1,
        CALCULATE(
            [000 Current_year_CNPVO_value],
            WINDOW(
                -1,
                REL,
                -1,
                REL,
                ALLSELECTED('PVO&CNI_BI'[YEAR]),
                ORDERBY('PVO&CNI_BI'[YEAR])
            )
        )
    )

VAR YoY = IF(ISBLANK(PreviousValue) || PreviousValue = 0, BLANK(), DIVIDE([000 Current_year_CNPVO_value] - PreviousValue, PreviousValue))
VAR MonthIndex = RANKX(ALLSELECTED('PVO&CNI_BI'[YEAR]), 'PVO&CNI_BI'[YEAR],,ASC)
VAR CurrentValue = [000 Current_year_CNPVO_value]
VAR BarHeight = Height_Bar * CurrentValue / MaxValue_CNPVO * 0.3 // YoY显示在柱子上的高度
VAR PositionX = (MonthIndex - 1) * Width_Bar + (Width_Bar - Width_BarAct_CNPVO) / 5.5
VAR BarCenterX = PositionX + Width_BarAct_CNPVO / 4  // 柱子中心X坐标
VAR PositionY = Height_Total_CNPVO - Height_ItemLabel - BarHeight - 45 - 10  // 向上移动10个单位
RETURN
IF(NOT ISBLANK(YoY),
    "<text x='" & BarCenterX & "' y='" & PositionY & 
    "' font-size='" & FontSize * 0.8 & "' text-anchor='middle' fill='" & 
    IF(YoY>0,"green","red") & "'>" & FORMAT(YoY,"▲0.0%;▼0.0%;-") & "</text>"
))

// 使用CNPVO的总高度作为SVG容器的高度
VAR _CSS = 
"body { background-image: url(""data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='" &  Width_Total & "' height='" & Height_Total_CNPVO & "'><path d='M" & FirstBarCenterX & " " & Height_Total_CNPVO - Height_ItemLabel - Height_Bar * FirstValue / MaxValue_CNPVO & "L" & FirstBarCenterX & " " & SpaceAboveRect * 0.2 & " " &  LastBarCenterX & " " & SpaceAboveRect * 0.2 & " " & LastBarCenterX & " " & Height_Total_CNPVO - Height_ItemLabel - Height_Bar * LastValue / MaxValue_CNPVO & "' fill='none' stroke='lightgrey' stroke-width='1.5' stroke-dasharray='5 2'/><path d='M" & Width_Total / 2 - Width_Bar  & " " & SpaceAboveRect * 0.2  & "L" & Width_Total / 2 & " " & SpaceAboveRect * 0.1 & " " &  Width_Total / 2 + Width_Bar   & " " & SpaceAboveRect * 0.2 & " " & Width_Total / 2 & " " & SpaceAboveRect * 0.3 & "' fill='" & IF (Gap>0,"green","tomato") &"'/><text x='" & Width_Total / 2 & "' y='" & SpaceAboveRect * 0.25 & "' font-size='" & FontSize & "' text-anchor='middle' fill='snow'>" & FORMAT(Gap,"+0.0%;-0.0%;-") & "</text><text x='" & LastBarCenterX & "' y='" & Height_Total_CNPVO - Height_ItemLabel - Height_Bar * LastValue / MaxValue_CNPVO - 15 & "' font-size='12' text-anchor='middle' fill='grey'>▼</text>" & HorizontalBars & CONCATENATEX(LineBtw,[line]) & "</svg>"");background-repeat: no-repeat; }" & "
#htmlContent {
    display: flex; 
    flex-wrap: nowrap; 
    overflow-x: auto;
    white-space: nowrap; 
}"
RETURN IF(n>1,_CSS)

代码部分确实有一点复杂,大家可以参照代码后面所标的注释一同理解,如果大家想要套用,只需修改表以及列的相关变量即可。

接着,我们拖入刚刚创建的第一个长度量值名称为【Bar_PVO】到Values部分,Year为表格中日期维度。

然后把第二个长度量值【Style Sheet】拖入到该视觉对象Format下的【Style Sheet】中

接着我们就得到了所想要制作的效果。


文章转载自:

http://o9TnZkYQ.zLqyj.cn
http://32cz1Jtw.zLqyj.cn
http://oRjZlTwu.zLqyj.cn
http://Di4PUgte.zLqyj.cn
http://IJlTb7dk.zLqyj.cn
http://RWuyhP3H.zLqyj.cn
http://FMmWxU8F.zLqyj.cn
http://QqNc1E82.zLqyj.cn
http://wnxNX4d6.zLqyj.cn
http://A3xpDdbA.zLqyj.cn
http://FT07D03V.zLqyj.cn
http://7EV4kjvT.zLqyj.cn
http://XCHxajnK.zLqyj.cn
http://7HVdPWFg.zLqyj.cn
http://3QzTn8iX.zLqyj.cn
http://Ihqqz4gA.zLqyj.cn
http://5Z3JZUz9.zLqyj.cn
http://nxITj1M8.zLqyj.cn
http://2KNrEuhx.zLqyj.cn
http://MrQAO9LD.zLqyj.cn
http://X7MRurd2.zLqyj.cn
http://QXzAYj02.zLqyj.cn
http://ZMd3QQPe.zLqyj.cn
http://xIUj6Qfy.zLqyj.cn
http://fpci1NAA.zLqyj.cn
http://zmWNmP8J.zLqyj.cn
http://0aXs0vBj.zLqyj.cn
http://zlvl7TrP.zLqyj.cn
http://F4KZjvzE.zLqyj.cn
http://plHW2o6h.zLqyj.cn
http://www.dtcms.com/a/386317.html

相关文章:

  • Spring 介绍
  • 使用爱思助手(版本8.16)将ipa安装到ios
  • 大模型应用开发2-SpringAI实战
  • 【面板数据】上市公司校企合作论文发表数据集(2002-2025年)
  • MySQL的底层数据结构:B+树
  • 【Linux】LRU缓存(C++模拟实现)
  • 冲击成本敏感度曲线驱动的拆单频率参数动态调优机制
  • Typera+Gitee+PicGo 配置markdown专用图床
  • 正则化:机器学习泛化能力的守护神
  • GCKontrol对嵌入式设备FPGA设计流程的高效优化
  • vue2+vue3-自定义指令
  • Vue基础知识点(接上篇案例)
  • 动物排队+分手厨房?合作模拟《Pao Pao》登录steam
  • 易境通货代系统:如何实现全流程自动化报关管理?
  • OpenCV:答题卡识别
  • leetcode HOT100 个人理解及解析
  • 深入落地“人工智能+”,如何构建安全、高效的算力基础设施?
  • 无人出租车(Robotaxi)还有哪些技术瓶颈?
  • 安全开发生命周期管理
  • 用住宿楼模型彻底理解Kubernetes架构(运行原理视角)
  • 【大模型】minimind2 1: ubuntu24.04安装部署 web demo
  • 扩散模型之(八)Rectified Flow
  • Facebook主页变现功能被封?跨境玩家该如何申诉和预防
  • 《Java接入支付宝沙箱支付全流程详解》
  • DevOps实战(8) - 使用Arbess+GitLab+PostIn实现Go项目自动化部署
  • 趣味学RUST基础篇(高级特征)
  • 随机森林(Random Forest)学习笔记
  • css之Flex响应式多列布局,根据容器宽度自动调整显示2列或3列布局,支持多行排列
  • HTML应用指南:利用POST请求获取全国中石化易捷门店位置信息
  • PDF24 Creator:免费全能的PDF处理工具