MATLAB | 绘图复刻(十四) | 右侧对齐桑基图,及工具函数SSankey更新

本文主要是介绍MATLAB | 绘图复刻(十四) | 右侧对齐桑基图,及工具函数SSankey更新,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

hey 真的好久不见了,本期既是一期绘图复刻教程,也是我写的工具函数的版本更新,本期复刻的图片来自《Nature》:

  • Elmarakeby, H.A., Hwang, J., Arafeh, R. et al. Biologically informed deep neural network for prostate cancer discovery. Nature 598, 348–352 (2021). https://doi.org/10.1038/s41586-021-03922-4

绘图复刻效果如下:

本文所用工具函数的基本使用教程可参见以下文章:
https://blog.csdn.net/slandarer/article/details/130430147

该文章仅展示工具函数基本使用方法,本文需要用到文末2.0.0版本工具函数

该文章仅展示工具函数基本使用方法,本文需要用到文末2.0.0版本工具函数



绘图复刻教程部分

0 数据

本文所使用的数据大概长这样,存储在.mat文件中:

load('natureRandData.mat')

该文件依旧可以在文末所示仓库获取,当然这组数据是通过以下方式随机生成的,直接复制以下代码也是可以的:

% rng(5)
% SourceValue=[60,40,30];
% LayerNum=[3,10,10,10,10,10,6,1];
% links{1,3}='';
% for k=1
%     TargetValue=zeros(1,LayerNum(k+1));
%     for i=1:LayerNum(k)
%         tValue=randi([1,13],[1,LayerNum(k+1)]);
%         tValue=tValue./sum(tValue).*SourceValue(i);
%         for j=1:LayerNum(k+1)
%             TargetValue(j)=TargetValue(j)+tValue(j);
%             if tValue(j)>eps
%                 tLen=size(links,1);
%                 links{tLen+1,1}=[char(64+k),num2str(i)];
%                 links{tLen+1,2}=[char(64+k+1),num2str(j)];
%                 links{tLen+1,3}=tValue(j);
%             end
%         end
%     end
%     SourceValue=TargetValue;
% end
% links(1,:)=[];
% tResidual=0;
% for k=2:5
%     [~,tindex]=sort(rand([1,10]));
%     for i=1:10
%         tLen=size(links,1);
%         TargetValue(tindex(i))=SourceValue(i);
%         links{tLen+1,1}=[char(64+k),num2str(i)];
%         links{tLen+1,2}=[char(64+k+1),num2str(tindex(i))];
%         links{tLen+1,3}=SourceValue(i);
%     end
%     for i=1:10
%         tLen=size(links,1);
%         links{tLen+1,1}=['Residual-',char(64+k)];
%         links{tLen+1,2}=[char(64+k+1),num2str(tindex(i))];
%         tValue=rand([1,1])*20./(k.^1);
%         links{tLen+1,3}=tValue;
%         if k==2,tResidual=tResidual+tValue;end
%         if k==5,TargetValue(i)=TargetValue(i)+tValue;end
%     end
%     SourceValue=TargetValue;
% end
% k=1;tValue=randi([1,13],[1,3]);
% for i=1:3
%     tLen=size(links,1);
%     links{tLen+1,1}=[char(64+k),num2str(i)];
%     links{tLen+1,2}=['Residual-',char(64+k+1)];
%     links{tLen+1,3}=tValue(i)./sum(tValue).*tResidual;
% end
% for k=6
%     TargetValue=zeros(1,LayerNum(k+1));
%     for i=1:LayerNum(k)
%         tValue=randi([1,13],[1,LayerNum(k+1)]);
%         tValue=tValue./sum(tValue).*SourceValue(i);
%         for j=1:LayerNum(k+1)
%             TargetValue(j)=TargetValue(j)+tValue(j);
%             if tValue(j)>eps
%                 tLen=size(links,1);
%                 links{tLen+1,1}=[char(64+k),num2str(i)];
%                 links{tLen+1,2}=[char(64+k+1),num2str(j)];
%                 links{tLen+1,3}=tValue(j);
%             end
%         end
%     end
%     SourceValue=TargetValue;
% end
% k=7;
% for i=1:LayerNum(end-1)
%     tLen=size(links,1);
%     links{tLen+1,1}=[char(64+k),num2str(i)];
%     links{tLen+1,2}=' ';
%     links{tLen+1,3}=SourceValue(i);
% end
% save natureRandData.mat links

1 配色

配色数据就是随便找个颜色提取器提取的论文原图:

CList1=[233,163,117; 150,209,224; 78 ,115,180]./255;
CList2=[149, 77, 85; 182, 85, 90; 208, 91, 94;208, 91, 94; 245,124,112; 252,150,128;252,173,151; 253,196,176; 253,217,203;254,236,228; 230,230,230]./255;

2 基础绘图

% 创建桑基图对象(Create a Sankey diagram object)
SK=SSankey(links(:,1),links(:,2),links(:,3));% % 类似于向右侧对齐
% SK.LayerOrder='reverse';% 修改链接颜色渲染方式(Set link color rendering method)
% 'left'/'right'/'interp'(default)/'map'/'simple'
SK.RenderingMethod='left';  % 修改对齐方式(Set alignment)
% 'up'/'down'/'center'(default)
SK.Align='center';% 修改文本位置(Set Text Location)
% 'left'(default)/'right'/'top'/'center'/'bottom'
SK.LabelLocation='right';% 设置缝隙占比(Separation distance proportion)
SK.Sep=0.02;
% SK.Sep=[.08,.04,.02,.05,.05,.06,.07];% 设置方块占比(Set the scale of blocks)
% BlockScale>0 & BlockScale<1
SK.BlockScale=.16;% 设置颜色(Set color)
SK.ColorList=[CList1;CList2(1:11,:)CList2(1:11,:)CList2(1:11,:)CList2(1:11,:)CList2(1:10,:)CList2(1:6,:)CList2(1,:)];% 开始绘图(Start drawing)
SK.draw()


3 右侧对齐

我们发现此时有的Residual方块由于左侧没有方块会被排列在最左侧,这样会比较混乱,此时选择将LayerOrder设置为反方向(此操作要在SK.draw()之前):

% 类似于向右侧对齐
SK.LayerOrder='reverse';


4 自定义缝隙比例

我们发现由于流入流出数据不相等,越往右侧整体会越窄,而原图基本上是两端对齐的,因此我们可以调整每一层的缝隙占比,比如(此操作要在SK.draw()之前):

% 设置缝隙占比(Separation distance proportion)
% SK.Sep=0.02;
SK.Sep=[.08,.04,.02,.05,.05,.06,.07];


5 节点方块修饰

加个白框:

for i=1:SK.BNSK.setBlock(i,'EdgeColor',[1,1,1],'LineWidth',1)
end


6 添加标签

就直接用text硬画,第i层的横坐标就是i,而宽度是SK.BlockScale,因此比较容易找到每层的X方向中点:

FontCell={'FontSize',22,'FontName','Times New Roman','HorizontalAlignment','center','VerticalAlignment','bottom'};
for i=2:SK.LN-1text(i+SK.BlockScale/2,min(min(SK.LayerPos(:,3:4))),['H',num2str(i-1)],FontCell{:})
end
text(1+SK.BlockScale/2,min(min(SK.LayerPos(:,3:4))),'Input',FontCell{:})
text(8+SK.BlockScale/2,min(min(SK.LayerPos(:,3:4))),'OutCome',FontCell{:})


绘图复刻完整代码

% -----------------------------------------------------+
% @author  | slandarer                                 |
% -----------------------------------------------------+
% 复刻自   | www.nature.com/articles/s41586-021-03922-4 |
% -----------------------------------------------------+figure('Name','nature sankey demo','Units','normalized','Position',[.05,.2,.9,.56])
clc;clear;%% 配色 ===================================================================
CList1=[233,163,117; 150,209,224; 78 ,115,180]./255;
CList2=[149, 77, 85; 182, 85, 90; 208, 91, 94;208, 91, 94; 245,124,112; 252,150,128;252,173,151; 253,196,176; 253,217,203;254,236,228; 230,230,230]./255;
%% 随意构造数据 ============================================================
load('natureRandData.mat')%% 绘图主要代码 ============================================================
% 创建桑基图对象(Create a Sankey diagram object)
SK=SSankey(links(:,1),links(:,2),links(:,3));% 类似于向右侧对齐
SK.LayerOrder='reverse';% 修改链接颜色渲染方式(Set link color rendering method)
% 'left'/'right'/'interp'(default)/'map'/'simple'
SK.RenderingMethod='left';  % 修改对齐方式(Set alignment)
% 'up'/'down'/'center'(default)
SK.Align='center';% 修改文本位置(Set Text Location)
% 'left'(default)/'right'/'top'/'center'/'bottom'
SK.LabelLocation='right';% 设置缝隙占比(Separation distance proportion)
% SK.Sep=0.02;
SK.Sep=[.08,.04,.02,.05,.05,.06,.07];% 设置方块占比(Set the scale of blocks)
% BlockScale>0 & BlockScale<1
SK.BlockScale=.16;% 设置颜色(Set color)
SK.ColorList=[CList1;CList2(1:11,:)CList2(1:11,:)CList2(1:11,:)CList2(1:11,:)CList2(1:10,:)CList2(1:6,:)CList2(1,:)];% 开始绘图(Start drawing)
SK.draw()
%% 修饰 ===================================================================for i=1:SK.BNSK.setBlock(i,'EdgeColor',[1,1,1],'LineWidth',1)
end
FontCell={'FontSize',22,'FontName','Times New Roman','HorizontalAlignment','center','VerticalAlignment','bottom'};
for i=2:SK.LN-1text(i+SK.BlockScale/2,min(min(SK.LayerPos(:,3:4))),['H',num2str(i-1)],FontCell{:})
end
text(1+SK.BlockScale/2,min(min(SK.LayerPos(:,3:4))),'Input',FontCell{:})
text(8+SK.BlockScale/2,min(min(SK.LayerPos(:,3:4))),'OutCome',FontCell{:})

工具函数完整代码

classdef SSankey < handle
% Copyright (c) 2023, Zhaoxu Liu / slandarer
% =========================================================================
% @author : slandarer
% =========================================================================
% # update 2.0.0(2024-02-04)
% see natureSankeyDemo1.m
%
% + 层向右对齐(Align layers to the right)
%   try : obj.LayerOrder='reverse';
%
% + 单独调整每层间隙大小(Adjust the Sep size of each layer separately)
%   try : obj..Sep=[.2,.06,.05,.07,.07,.08,.15];
% propertiesSource;Target;Value;SourceInd;TargetInd;Layer;LayerPos;LayerOrder='normal';AdjMat;BoolMat;RenderingMethod='interp'  % 'left'/'right'/'interp'/'map'/'simple'LabelLocation='left'      % 'left'/'right'/'top'/'center'/'bottom'Align='center'            % 'up'/'down'/'center'BlockScale=0.05;          %  BlockScale>0 ! !Sep=0.05;                 %  Sep>=0 ! !NodeList={};ColorList=[[65,140,240;252,180,65;224,64,10;5,100,146;191,191,191;26,59,105;255,227,130;18,156,221;202,107,75;0,92,219;243,210,136;80,99,129;241,185,168;224,131,10;120,147,190]./255;[127,91,93;187,128,110;197,173,143;59,71,111;104,95,126;76,103,86;112,112,124;72,39,24;197,119,106;160,126,88;238,208,146]./255];BlockHdl;LinkHdl;LabelHdl;ax;Parent;BN;LN;VN;TotalLen;SepLen;arginList={'RenderingMethod','LabelLocation','BlockScale',...'Sep','Align','ColorList','Parent','NameList'}end
% 构造函数 =================================================================methodsfunction obj=SSankey(varargin)% 获取基本数据 -------------------------------------------------if isa(varargin{1},'matlab.graphics.axis.Axes')obj.ax=varargin{1};varargin(1)=[];else  endobj.Source=varargin{1};obj.Target=varargin{2};obj.Value=varargin{3};varargin(1:3)=[];% 获取其他信息 -------------------------------------------------for i=1:2:(length(varargin)-1)tid=ismember(obj.arginList,varargin{i});if any(tid)obj.(obj.arginList{tid})=varargin{i+1};endendif isempty(obj.ax)&&(~isempty(obj.Parent)),obj.ax=obj.Parent;endif isempty(obj.ax),obj.ax=gca;endobj.ax.NextPlot='add';% 基本数据预处理 -----------------------------------------------if isempty(obj.NodeList)obj.NodeList=[obj.Source;obj.Target];obj.NodeList=unique(obj.NodeList,'stable');endobj.BN=length(obj.NodeList);if length(obj.NodeList)>size(obj.ColorList,1)obj.ColorList=[obj.ColorList;rand(length(obj.NodeList),3).*.7];endobj.VN=length(obj.Value);% 坐标区域基础设置 ---------------------------------------------obj.ax.YDir='reverse';obj.ax.XColor='none';obj.ax.YColor='none';end
% 绘图函数 =================================================================function draw(obj)% 生成整体邻接矩阵 ---------------------------------------------obj.AdjMat=zeros(obj.BN,obj.BN);for i=1:length(obj.Source)obj.SourceInd(i)=find(strcmp(obj.Source{i},obj.NodeList));obj.TargetInd(i)=find(strcmp(obj.Target{i},obj.NodeList));obj.AdjMat(obj.SourceInd(i),obj.TargetInd(i))=obj.Value{i};endobj.BoolMat=abs(obj.AdjMat)>0;% 计算每个对象位于的层、每层方块长度、每个方块位置 ----------------if strcmp(obj.LayerOrder,'normal')obj.Layer=zeros(obj.BN,1);obj.Layer(sum(obj.BoolMat,1)==0)=1;startMat=diag(obj.Layer);for i=1:(obj.BN-1)tLayer=(sum(startMat*obj.BoolMat^i,1)>0).*(i+1);obj.Layer=max([obj.Layer,tLayer'],[],2);endelseobj.Layer=zeros(obj.BN,1);obj.Layer(sum(obj.BoolMat,2)==0)=-1;startMat=diag(obj.Layer);for i=1:(obj.BN-1)tLayer=(sum(startMat*(obj.BoolMat.')^i,1)<0).*(-i-1);obj.Layer=min([obj.Layer,tLayer'],[],2);endobj.Layer=obj.Layer-min(obj.Layer)+1;endobj.LN=max(obj.Layer);obj.TotalLen=max([sum(obj.AdjMat,1).',sum(obj.AdjMat,2)],[],2);obj.SepLen=max(obj.TotalLen).*obj.Sep;obj.LayerPos=zeros(obj.BN,4);for i=1:obj.LNtBlockInd=find(obj.Layer==i);tBlockLen=[0;cumsum(obj.TotalLen(tBlockInd))];tY1=tBlockLen(1:end-1)+(0:length(tBlockInd)-1).'.*obj.SepLen(min(i,length(obj.Sep)));tY2=tBlockLen(2:end)+(0:length(tBlockInd)-1).'.*obj.SepLen(min(i,length(obj.Sep)));obj.LayerPos(tBlockInd,3)=tY1;obj.LayerPos(tBlockInd,4)=tY2;% for j=1:length(tY2)%     plot([i,i],[tY1(j),tY2(j)],'LineWidth',2)% endendobj.LayerPos(:,1)=obj.Layer;obj.LayerPos(:,2)=obj.Layer+obj.BlockScale;% 根据对齐方式调整Y坐标 -----------------------------------------tMinY=min(obj.LayerPos(:,3));tMaxY=max(obj.LayerPos(:,4));for i=1:obj.LNtBlockInd=find(obj.Layer==i);tBlockPos3=obj.LayerPos(tBlockInd,3);tBlockPos4=obj.LayerPos(tBlockInd,4);switch obj.Aligncase 'up'case 'down'obj.LayerPos(tBlockInd,3)=obj.LayerPos(tBlockInd,3)+tMaxY-max(tBlockPos4);obj.LayerPos(tBlockInd,4)=obj.LayerPos(tBlockInd,4)+tMaxY-max(tBlockPos4);case 'center'obj.LayerPos(tBlockInd,3)=obj.LayerPos(tBlockInd,3)+...min(tBlockPos3)/2-max(tBlockPos4)/2+tMinY/2-tMaxY/2;obj.LayerPos(tBlockInd,4)=obj.LayerPos(tBlockInd,4)+...min(tBlockPos3)/2-max(tBlockPos4)/2+tMinY/2-tMaxY/2;endend% 绘制连接 -----------------------------------------------------for i=1:obj.VNtSource=obj.SourceInd(i);tTarget=obj.TargetInd(i);tS1=sum(obj.AdjMat(tSource,1:(tTarget-1)))+obj.LayerPos(tSource,3);tS2=sum(obj.AdjMat(tSource,1:tTarget))+obj.LayerPos(tSource,3);tT1=sum(obj.AdjMat(1:(tSource-1),tTarget))+obj.LayerPos(tTarget,3);tT2=sum(obj.AdjMat(1:tSource,tTarget))+obj.LayerPos(tTarget,3);if isempty(tS1),tS1=0;endif isempty(tT1),tT1=0;endtX=[obj.LayerPos(tSource,1),obj.LayerPos(tSource,2),obj.LayerPos(tTarget,1),obj.LayerPos(tTarget,2)];qX=linspace(obj.LayerPos(tSource,1),obj.LayerPos(tTarget,2),200);qT=linspace(0,1,50);qY1=interp1(tX,[tS1,tS1,tT1,tT1],qX,'pchip');qY2=interp1(tX,[tS2,tS2,tT2,tT2],qX,'pchip');XX=repmat(qX,[50,1]);YY=qY1.*(qT'.*0+1)+(qY2-qY1).*(qT');MeshC=ones(50,200,3);switch obj.RenderingMethodcase 'left'MeshC(:,:,1)=MeshC(:,:,1).*obj.ColorList(tSource,1);MeshC(:,:,2)=MeshC(:,:,2).*obj.ColorList(tSource,2);MeshC(:,:,3)=MeshC(:,:,3).*obj.ColorList(tSource,3);case 'right'MeshC(:,:,1)=MeshC(:,:,1).*obj.ColorList(tTarget,1);MeshC(:,:,2)=MeshC(:,:,2).*obj.ColorList(tTarget,2);MeshC(:,:,3)=MeshC(:,:,3).*obj.ColorList(tTarget,3);case 'interp'MeshC(:,:,1)=repmat(linspace(obj.ColorList(tSource,1),obj.ColorList(tTarget,1),200),[50,1]);MeshC(:,:,2)=repmat(linspace(obj.ColorList(tSource,2),obj.ColorList(tTarget,2),200),[50,1]);MeshC(:,:,3)=repmat(linspace(obj.ColorList(tSource,3),obj.ColorList(tTarget,3),200),[50,1]);case 'map'MeshC=MeshC(:,:,1).*obj.Value{i};case 'simple'MeshC(:,:,1)=MeshC(:,:,1).*.6;MeshC(:,:,2)=MeshC(:,:,2).*.6;MeshC(:,:,3)=MeshC(:,:,3).*.6;endobj.LinkHdl(i)=surf(obj.ax,XX,YY,XX.*0,'EdgeColor','none','FaceAlpha',.3,'CData',MeshC);end% 绘制方块 -----------------------------------------------------for i=1:obj.BNobj.BlockHdl(i)=fill(obj.ax,obj.LayerPos(i,[1,2,2,1]),...obj.LayerPos(i,[3,3,4,4]),obj.ColorList(i,:),'EdgeColor','none');end% 绘制文本 -----------------------------------------------------for i=1:obj.BNswitch obj.LabelLocationcase 'right'obj.LabelHdl(i)=text(obj.ax,obj.LayerPos(i,2),mean(obj.LayerPos(i,[3,4])),...[' ',obj.NodeList{i}],'FontSize',15,'FontName','Times New Roman','HorizontalAlignment','left');case 'left'obj.LabelHdl(i)=text(obj.ax,obj.LayerPos(i,1),mean(obj.LayerPos(i,[3,4])),...[obj.NodeList{i},' '],'FontSize',15,'FontName','Times New Roman','HorizontalAlignment','right');case 'top'obj.LabelHdl(i)=text(obj.ax,mean(obj.LayerPos(i,[1,2])),obj.LayerPos(i,3),...obj.NodeList{i},'FontSize',15,'FontName','Times New Roman','HorizontalAlignment','center','VerticalAlignment','bottom');case 'center'obj.LabelHdl(i)=text(obj.ax,mean(obj.LayerPos(i,[1,2])),mean(obj.LayerPos(i,[3,4])),...obj.NodeList{i},'FontSize',15,'FontName','Times New Roman','HorizontalAlignment','center');case 'bottom'obj.LabelHdl(i)=text(obj.ax,mean(obj.LayerPos(i,[1,2])),obj.LayerPos(i,4),...obj.NodeList{i},'FontSize',15,'FontName','Times New Roman','HorizontalAlignment','center','VerticalAlignment','top');endend% -------------------------------------------------------------axis tight;help SSankeyend
% =========================================================================function setBlock(obj,n,varargin)set(obj.BlockHdl(n),varargin{:})endfunction setLink(obj,n,varargin)set(obj.LinkHdl(n),varargin{:})endfunction setLabel(obj,n,varargin)set(obj.LabelHdl(n),varargin{:})endfunction moveBlockY(obj,n,dy)obj.LayerPos(n,[3,4])=obj.LayerPos(n,[3,4])-dy;set(obj.BlockHdl(n),'YData',obj.LayerPos(n,[3,3,4,4]));switch obj.LabelLocationcase 'right',set(obj.LabelHdl(n),'Position',[obj.LayerPos(n,2),mean(obj.LayerPos(n,[3,4]))]);case 'left',set(obj.LabelHdl(n),'Position',[obj.LayerPos(n,1),mean(obj.LayerPos(n,[3,4]))]);case 'top',set(obj.LabelHdl(n),'Position',[mean(obj.LayerPos(n,[1,2])),obj.LayerPos(n,3)]);case 'center',set(obj.LabelHdl(n),'Position',[mean(obj.LayerPos(n,[1,2])),mean(obj.LayerPos(n,[3,4]))]);case 'bottom',set(obj.LabelHdl(n),'Position',[mean(obj.LayerPos(n,[1,2])),obj.LayerPos(n,4)]);endfor i=1:obj.VNtSource=obj.SourceInd(i);tTarget=obj.TargetInd(i);if tSource==n||tTarget==ntS1=sum(obj.AdjMat(tSource,1:(tTarget-1)))+obj.LayerPos(tSource,3);tS2=sum(obj.AdjMat(tSource,1:tTarget))+obj.LayerPos(tSource,3);tT1=sum(obj.AdjMat(1:(tSource-1),tTarget))+obj.LayerPos(tTarget,3);tT2=sum(obj.AdjMat(1:tSource,tTarget))+obj.LayerPos(tTarget,3);if isempty(tS1),tS1=0;endif isempty(tT1),tT1=0;endtX=[obj.LayerPos(tSource,1),obj.LayerPos(tSource,2),obj.LayerPos(tTarget,1),obj.LayerPos(tTarget,2)];qX=linspace(obj.LayerPos(tSource,1),obj.LayerPos(tTarget,2),200);qT=linspace(0,1,50);qY1=interp1(tX,[tS1,tS1,tT1,tT1],qX,'pchip');qY2=interp1(tX,[tS2,tS2,tT2,tT2],qX,'pchip');YY=qY1.*(qT'.*0+1)+(qY2-qY1).*(qT');set(obj.LinkHdl(i),'YData',YY);endendendend
% Copyright (c) 2023, Zhaoxu Liu / slandarer
% =========================================================================
% @author : slandarer
% -------------------------------------------------------------------------
end

以上已经是完整代码,对于工具函数2.0.0更新版,未经允许本代码请勿作商业用途,引用的话可以引用我file exchange上的链接,可使用如下格式:

Zhaoxu Liu / slandarer (2023). sankey plot (https://www.mathworks.com/matlabcentral/fileexchange/128679-sankey-plot), MATLAB Central File Exchange. 检索来源 2023/4/28.

若转载请保留以上file exchange链接及本文链接!!!!!

该工具可通过上述fileexchange链接获取,或者通过以下gitee仓库下载:

https://gitee.com/slandarer/matlab-sankey-diagram


对于绘图复刻以及.mat文件,可以去以下gitee仓库获取全部代码:

https://gitee.com/slandarer/PLTreprint/

这篇关于MATLAB | 绘图复刻(十四) | 右侧对齐桑基图,及工具函数SSankey更新的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/677857

相关文章

基于Python实现简易视频剪辑工具

《基于Python实现简易视频剪辑工具》这篇文章主要为大家详细介绍了如何用Python打造一个功能完备的简易视频剪辑工具,包括视频文件导入与格式转换,基础剪辑操作,音频处理等功能,感兴趣的小伙伴可以了... 目录一、技术选型与环境搭建二、核心功能模块实现1. 视频基础操作2. 音频处理3. 特效与转场三、高

postgresql使用UUID函数的方法

《postgresql使用UUID函数的方法》本文给大家介绍postgresql使用UUID函数的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录PostgreSQL有两种生成uuid的方法。可以先通过sql查看是否已安装扩展函数,和可以安装的扩展函数

MySQL字符串常用函数详解

《MySQL字符串常用函数详解》本文给大家介绍MySQL字符串常用函数,本文结合实例代码给大家介绍的非常详细,对大家学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录mysql字符串常用函数一、获取二、大小写转换三、拼接四、截取五、比较、反转、替换六、去空白、填充MySQL字符串常用函数一、

基于Python开发一个图像水印批量添加工具

《基于Python开发一个图像水印批量添加工具》在当今数字化内容爆炸式增长的时代,图像版权保护已成为创作者和企业的核心需求,本方案将详细介绍一个基于PythonPIL库的工业级图像水印解决方案,有需要... 目录一、系统架构设计1.1 整体处理流程1.2 类结构设计(扩展版本)二、核心算法深入解析2.1 自

SpringBoot中六种批量更新Mysql的方式效率对比分析

《SpringBoot中六种批量更新Mysql的方式效率对比分析》文章比较了MySQL大数据量批量更新的多种方法,指出REPLACEINTO和ONDUPLICATEKEY效率最高但存在数据风险,MyB... 目录效率比较测试结构数据库初始化测试数据批量修改方案第一种 for第二种 case when第三种

C++中assign函数的使用

《C++中assign函数的使用》在C++标准模板库中,std::list等容器都提供了assign成员函数,它比操作符更灵活,支持多种初始化方式,下面就来介绍一下assign的用法,具有一定的参考价... 目录​1.assign的基本功能​​语法​2. 具体用法示例​​​(1) 填充n个相同值​​(2)

MySql基本查询之表的增删查改+聚合函数案例详解

《MySql基本查询之表的增删查改+聚合函数案例详解》本文详解SQL的CURD操作INSERT用于数据插入(单行/多行及冲突处理),SELECT实现数据检索(列选择、条件过滤、排序分页),UPDATE... 目录一、Create1.1 单行数据 + 全列插入1.2 多行数据 + 指定列插入1.3 插入否则更

PostgreSQL中rank()窗口函数实用指南与示例

《PostgreSQL中rank()窗口函数实用指南与示例》在数据分析和数据库管理中,经常需要对数据进行排名操作,PostgreSQL提供了强大的窗口函数rank(),可以方便地对结果集中的行进行排名... 目录一、rank()函数简介二、基础示例:部门内员工薪资排名示例数据排名查询三、高级应用示例1. 每

全面掌握 SQL 中的 DATEDIFF函数及用法最佳实践

《全面掌握SQL中的DATEDIFF函数及用法最佳实践》本文解析DATEDIFF在不同数据库中的差异,强调其边界计算原理,探讨应用场景及陷阱,推荐根据需求选择TIMESTAMPDIFF或inte... 目录1. 核心概念:DATEDIFF 究竟在计算什么?2. 主流数据库中的 DATEDIFF 实现2.1

MySQL中的LENGTH()函数用法详解与实例分析

《MySQL中的LENGTH()函数用法详解与实例分析》MySQLLENGTH()函数用于计算字符串的字节长度,区别于CHAR_LENGTH()的字符长度,适用于多字节字符集(如UTF-8)的数据验证... 目录1. LENGTH()函数的基本语法2. LENGTH()函数的返回值2.1 示例1:计算字符串