国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

前端可視化入門與實(shí)戰(zhàn):D3 高級(jí)圖表實(shí)戰(zhàn):柱狀圖、折線圖

這篇具有很好參考價(jià)值的文章主要介紹了前端可視化入門與實(shí)戰(zhàn):D3 高級(jí)圖表實(shí)戰(zhàn):柱狀圖、折線圖。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

前端可視化入門與實(shí)戰(zhàn) - 謙宇 - 掘金小冊(cè)

在上一節(jié)我們介紹了 SVG 的進(jìn)階使用及圖表實(shí)現(xiàn),但是單純用 SVG 實(shí)現(xiàn)圖表,會(huì)有一個(gè)很大的問(wèn)題,就是沒(méi)有規(guī)范,正規(guī)封裝圖表庫(kù),我們需要封裝大量的基礎(chǔ)類和通用方法,比如需要封裝適配不同數(shù)據(jù)的比例尺。

如果我們前期不去做這些繁瑣的基礎(chǔ)工作,就會(huì)讓后期維護(hù)越來(lái)越難,而 D3 的 V3 版本是基于 SVG 的,并且已經(jīng)做了底層的封裝,更方便我們維護(hù)和快速開發(fā)。本文將以為什么要用 D3 開始,然后深入淺出說(shuō)明 D3 的用法,最后學(xué)以致用,一起來(lái)實(shí)現(xiàn)柱狀圖、多層級(jí)旋轉(zhuǎn)標(biāo)簽柱狀圖、折線圖、動(dòng)態(tài)排序折線圖。

為什么要用 D3

使用 D3.js 開發(fā)可視化圖表有以下幾個(gè)優(yōu)點(diǎn)。

  1. 功能豐富:D3.js 提供了許多豐富的數(shù)據(jù)可視化功能,比如縮放、交互、布局、動(dòng)畫等等,能夠幫助開發(fā)者快速創(chuàng)作各種類型的圖表,并且容易擴(kuò)展。

  2. 自定義程度高:使用 D3.js 可以靈活控制所有圖表的元素,包括圖形、軸、標(biāo)簽、交互等等,可根據(jù)業(yè)務(wù)需求隨意定制化圖表。

  3. 界面友好:D3.js 提供了類似 JQuery 的 DOM 操作方法,偏向函數(shù)式編程,使開發(fā)者能夠方便地對(duì)圖表進(jìn)行操作,同時(shí) D3 還提供了大量的樣式和布局輔助方法,可以便捷地定義圖表樣式和布局。

  4. 社區(qū)活躍:D3.js 擁有龐大的開發(fā)社區(qū),有大量 D3.js 的相關(guān)資料、代碼示例和插件,能夠幫助開發(fā)者更加高效地開發(fā)可視化圖表。

  5. 兼容性好:D3.js 對(duì)各種瀏覽器的兼容性都很好,支持 IE6+ 和現(xiàn)代瀏覽器等多種瀏覽器,能夠保證圖表在各種不同瀏覽器環(huán)境下的穩(wěn)定性和可用性。

理解數(shù)據(jù)驅(qū)動(dòng)視圖

我們知道 D3 這個(gè)庫(kù)出色在于數(shù)據(jù)驅(qū)動(dòng)視圖的理念,那么如何理解呢?

在以往編寫 SVG、Canvas 都需要一行一行編寫樣式和屬性,并沒(méi)有一個(gè)統(tǒng)一的數(shù)據(jù)管理,數(shù)據(jù)和視圖關(guān)聯(lián)性很弱。所以,在 D3 中強(qiáng)調(diào)數(shù)據(jù),數(shù)據(jù)驅(qū)使視圖的更新,在 D3 中數(shù)據(jù)和 DOM 元素進(jìn)行綁定,并使用這些數(shù)據(jù)來(lái)更新元素的屬性、樣式、位置等,從而實(shí)現(xiàn)動(dòng)態(tài)的數(shù)據(jù)可視化效果,說(shuō)白了就是鏈?zhǔn)秸{(diào)用、狀態(tài)封裝來(lái)方便我們更新視圖。

理解數(shù)據(jù)驅(qū)動(dòng)視圖的理念后,我們?cè)诶L圖的時(shí)候要知道視圖元素和數(shù)據(jù)是強(qiáng)綁定的。當(dāng)知道數(shù)據(jù)是什么,通過(guò) D3 可以反推出元素的坐標(biāo)位置;當(dāng)知道元素的坐標(biāo)位置,也能知道數(shù)據(jù) data 是多少。比如,要獲取圖上 x 軸的數(shù)據(jù)對(duì)應(yīng)的 x 坐標(biāo),我們可以通過(guò)?xScale(value)?快速獲取。

實(shí)現(xiàn)柱狀圖

了解完 D3 的開發(fā)優(yōu)勢(shì)及出色理念后,下面我們一起來(lái)“理論結(jié)合實(shí)踐”,首先實(shí)現(xiàn)我們常用的柱狀圖。

其實(shí),實(shí)現(xiàn)柱狀圖等其他圖都會(huì)遵循一個(gè)套路

  • 定義數(shù)據(jù)集;
  • 定義繪圖區(qū)域(安全邊界 margin + 生成 SVG 的繪圖區(qū)域);
  • 設(shè)置比例尺;
  • 生成坐標(biāo)軸;
  • 繪制圖元。

還是比較好理解的,對(duì)吧?接下來(lái)我們就按照這個(gè)“套路”,一步一步去實(shí)現(xiàn)我們想要的柱狀圖。

  1. 定義我們的數(shù)據(jù)集
 

js

復(fù)制代碼

// 數(shù)據(jù) const data = [ { label: "A", value: 20 }, { label: "B", value: 50 }, { label: "C", value: 30 }, { label: "D", value: 80 }, { label: "E", value: 40 }, ];

  1. 定義繪圖區(qū)域。定義我們基礎(chǔ)圖表所在的 SVG 可視區(qū)域內(nèi)部的某一塊位置,一般我們理解為安全區(qū)域的邊距,以防止圖表某些元素丟失。
 

js

復(fù)制代碼

// 配置 const margin = { top: 20, right: 20, bottom: 30, left: 40 }; const width = 960 - margin.left - margin.right; const height = 500 - margin.top - margin.bottom;

下面我們將添加我們的繪制區(qū)域,select 類似我們 querySelector 查找對(duì)應(yīng)容器,設(shè)置寬和高,傳入 g 標(biāo)簽(g 標(biāo)簽用于分組,類似 div),然后移動(dòng)到對(duì)應(yīng)位置。

 

js

復(fù)制代碼

const svg = d3.select("#chart") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  1. 設(shè)置比例尺
 

js

復(fù)制代碼

const x = d3.scaleBand() .domain(data.map(function (d) { return d.label; })) .range([0, width]) .padding(0.1); const y = d3.scaleLinear() .domain([0, d3.max(data, function (d) { return d.value; })]) .range([height, 0]);

上文通過(guò) scaleBand 離散數(shù)據(jù)的比例尺傳入?domain(數(shù)據(jù)域)?,然后 range 定義值的范圍,讓每個(gè) label 的值映射到 range 的?[0, width],最后設(shè)置 padding 代表柱子間的間距。在 Y 軸,我們一般是連續(xù)的值代表大小的關(guān)系,這個(gè)時(shí)候需要使用 scaleLinear 來(lái)實(shí)現(xiàn)。

為了更好地理解,下面我羅列了這些方法的解釋。

  • scaleBand:D3 的比例尺游程,用于將離散的數(shù)據(jù)到連續(xù)的空間范圍內(nèi),并按照一定的方式進(jìn)行分組和排序。在柱狀圖、條形圖等圖表中,通常用于定義 x 軸的比例尺,將不同的類別或標(biāo)簽映射成一定的長(zhǎng)度。

  • scaleLinear:D3 的線性比例尺,用于將連續(xù)的數(shù)據(jù)到連續(xù)的空間范圍內(nèi)。在柱狀圖、折線圖等圖表中,通常用于定義 y 軸的比例尺,將原始數(shù)據(jù)映射到實(shí)際的高度或者縱坐標(biāo)位置上。

  • domain:比例尺的定義域,表示原始數(shù)據(jù)的范圍。

  • range:比例尺的值域,表示將原始數(shù)據(jù)映射到的連續(xù)空間的范圍。

  • paddingd3.scaleBand()?比例尺中的分組間距,即每組數(shù)據(jù)之間的空白寬度。

為了避免有小伙伴有疑問(wèn),這里我也額外簡(jiǎn)單介紹下“數(shù)據(jù)域”和“比例尺”。

數(shù)據(jù)域

在數(shù)據(jù)可視化中,通常使用坐標(biāo)軸來(lái)表示數(shù)據(jù)的范圍。數(shù)據(jù)范圍指的是原始數(shù)據(jù)的取值范圍,而數(shù)據(jù)域(或稱值域)指的是數(shù)據(jù)在可視化過(guò)程中映射到畫布上的范圍

例如,假設(shè)有一個(gè)包含以下數(shù)據(jù)的數(shù)組:

[10, 20, 30, 40, 50]

這個(gè)數(shù)組的數(shù)據(jù)范圍為 10 到 50。我們可以使用線性比例尺將這些數(shù)據(jù)映射到值域?yàn)?0 到 400 的可視化空間上。在這種情況下,數(shù)據(jù)點(diǎn) 10 將映射到像素 0,數(shù)據(jù)點(diǎn) 50 將映射到像素 400。每個(gè)數(shù)據(jù)點(diǎn)在值域中對(duì)應(yīng)了一個(gè)唯一的像素位置。

比例尺

比例尺(Scale)是一種將數(shù)據(jù)值映射到視覺(jué)表示時(shí)使用的函數(shù)。它們將輸入域(例如數(shù)據(jù)的原始值)中的值映射到輸出域(例如圖表的坐標(biāo)軸長(zhǎng)度或顏色)中的值,以便更好地表現(xiàn)數(shù)據(jù)的分布和關(guān)系。

以下是其中幾種比例尺的標(biāo)準(zhǔn):

  • 線性比例尺,將坐標(biāo)軸上的數(shù)據(jù)線性地映射到屏幕上的像素值。例如,如果數(shù)據(jù)范圍從 0 到 100,則比例尺將保持?jǐn)?shù)據(jù)點(diǎn)之間的線性距離。這意味著在圖表上,兩個(gè)數(shù)據(jù)點(diǎn)之間的距離和它們?cè)谧鴺?biāo)軸上的距離是成比例的。線性比例尺適用于大多數(shù)情況,可以處理常規(guī)的數(shù)據(jù)范圍。
  • 對(duì)數(shù)比例尺,將坐標(biāo)軸上的數(shù)據(jù)按對(duì)數(shù)比例映射到屏幕上的像素值。對(duì)數(shù)比例尺的作用是將取值范圍很寬的數(shù)據(jù),壓縮到一個(gè)較小的范圍,以便更好地可視化。適合處理數(shù)據(jù)取值范圍較大,或者存在比例差異較大的場(chǎng)景。
  • 時(shí)間比例尺,將坐標(biāo)軸上的時(shí)間數(shù)據(jù)映射到屏幕上的像素值。時(shí)間比例尺通常用于可視化時(shí)間序列數(shù)據(jù),如股票價(jià)格、氣象數(shù)據(jù)等。以時(shí)間為坐標(biāo)軸的數(shù)據(jù),需要按照特定的粒度進(jìn)行組織和映射,如按天、按周、按月等。
  1. 生成坐標(biāo)軸
 

go

復(fù)制代碼

// X軸 svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(d3.axisBottom(x)); // Y軸 svg.append("g") .attr("class", "y axis") .call(d3.axisLeft(y).ticks(10));

這里需要注意 call 的用法用于修改 this 的指向,這里可以簡(jiǎn)單理解為將 SVG 的對(duì)象 this 綁定到?d3.axisBottom(x)?返回的構(gòu)造函數(shù)上,也就意味著這個(gè)構(gòu)造函數(shù)可以直接操作 SVG 對(duì)象,而不用多余傳入 SVG 對(duì)象。

  1. 繪制柱體

下面這段代碼的意思是,選擇 SVG 上所有 class 為 bar 的元素,若不存在則創(chuàng)建。然后將數(shù)據(jù)與選擇集綁定,由于元素未創(chuàng)建使用 enter 來(lái)創(chuàng)建占位的節(jié)點(diǎn),append 傳入 rect 代表創(chuàng)建矩形,最后定義類名、坐標(biāo)、寬高。

 

js

復(fù)制代碼

// 柱形 svg.selectAll(".bar") .data(data) .enter().append("rect") .attr("class", "bar") .attr("x", function (d) { return x(d.label); }) .attr("y", function (d) { return y(d.value); }) .attr("width", x.bandwidth()) .attr("height", function (d) { return height - y(d.value); });

繪制效果如下:

實(shí)現(xiàn)多層級(jí)旋轉(zhuǎn)標(biāo)簽柱狀圖

ECharts 的柱狀圖示例

有了上文的基礎(chǔ),我們接下來(lái)將要實(shí)現(xiàn)一個(gè)相對(duì)復(fù)雜業(yè)務(wù)場(chǎng)景下的 ECharts 的柱狀圖示例:

首先,我們要清楚這里只不過(guò)分了 4 個(gè)組,每個(gè)組放了 4 個(gè)季度的柱子,而柱子的間距我們可以通過(guò) padding 來(lái)實(shí)現(xiàn)。初學(xué)者可能很喜歡用循環(huán)來(lái)將每組進(jìn)行定位,其實(shí)在 D3 處理這些十分簡(jiǎn)單,我們可以像下面這樣不斷用類似同步的寫法避免嵌套,這樣的代碼十分容易維護(hù)。

 

js

復(fù)制代碼

const group = chart.selectAll(".group").data(data) group.selectAll("rect")

下面是代碼的整體實(shí)現(xiàn):

 

js

復(fù)制代碼

// 定義數(shù)據(jù)結(jié)構(gòu) // 定義數(shù)據(jù)結(jié)構(gòu) const data = [ { label: "2020", season: [ { label: "Q1", value: 300 }, { label: "Q2", value: 220 }, { label: "Q3", value: 80 }, { label: "Q4", value: 400 }, ], }, { label: "2021", season: [ { label: "Q1", value: 100 }, { label: "Q2", value: 20 }, { label: "Q3", value: 120 }, { label: "Q4", value: 20 }, ], }, { label: "2022", season: [ { label: "Q1", value: 100 }, { label: "Q2", value: 20 }, { label: "Q3", value: 120 }, { label: "Q4", value: 20 }, ], }, { label: "2023", season: [ { label: "Q1", value: 100 }, { label: "Q2", value: 20 }, { label: "Q3", value: 120 }, { label: "Q4", value: 20 }, ], }, ]; // 每年4個(gè)季度 const seasonLen = 4 // 統(tǒng)計(jì)年的數(shù)量 const yearLen = data.length const colors = ['#5470C6', '#91CC75', '#fac858', '#ee6666'] const svgWidth = 960; const svgHeight = 500; // 定義圖幅大小 const margin = { top: 50, right: 50, bottom: 50, left: 50 }; const chartWidth = svgWidth - margin.left - margin.right; const chartHeight = svgHeight - margin.top - margin.bottom; const svg = d3.select("svg") .attr("width", svgWidth) .attr("height", svgHeight); // 創(chuàng)建比例尺 const xScale = d3.scaleBand() .domain(data.map(d => d.label)) .range([0, chartWidth]) .padding(.2) const yScale = d3.scaleLinear() .domain([0, d3.max(data, d => d3.max(d.season, s => s.value))]) .range([chartHeight, 0]); // 獲取每個(gè)柱子的寬度 const columWidth = (xScale.bandwidth() / seasonLen) // 創(chuàng)建圖表的根節(jié)點(diǎn) const chart = svg.append("g") .attr("transform", `translate(${margin.left},${margin.top})`); // 創(chuàng)建坐標(biāo)軸 chart.append("g") .attr("transform", `translate(0,${chartHeight})`) .call(d3.axisBottom(xScale)); chart.append("g") .call(d3.axisLeft(yScale)); // 創(chuàng)建group組,存不同年份的分組節(jié)點(diǎn) const group = chart.selectAll(".group") .data(data) .enter() .append("g") .attr("class", "group") .attr("transform", (d) => `translate(${xScale(d.label) + columWidth},0)`); // 在這些分組節(jié)點(diǎn)中,插入每個(gè)季度的rect節(jié)點(diǎn) group.selectAll("rect") .data(d => d.season) .enter() .append("rect") .style('fill', (d, i) => colors[i]) .attr("x", d => columWidth * (["Q1", "Q2", "Q3", "Q4"].indexOf(d.label) - 1)) .attr("y", d => yScale(d.value)) .attr("width", xScale.bandwidth() / seasonLen) .attr("height", d => chartHeight - yScale(d.value));

實(shí)現(xiàn)效果如下:

坐標(biāo)軸優(yōu)化

我們可以發(fā)現(xiàn)坐標(biāo)軸出了細(xì)節(jié)問(wèn)題,我們需要去除 x 軸和 y 軸的刻度細(xì)線。

我們可以用 tickSizeOuter 清除 x 軸兩端的刻度。用 tickSize 清除內(nèi)部的刻度,在 y 軸我們控制下間隔后,同樣清除下兩端刻度。

 

js

復(fù)制代碼

d3.axisBottom(xScale).tickSizeOuter(0) d3.axisLeft(yScale).ticks(5).tickSizeOuter(0)

輔助線優(yōu)化

另外,y 軸的輔助線怎么實(shí)現(xiàn)呢?

其實(shí)我們可以利用刻度,因?yàn)榭潭缺旧砭褪?line 標(biāo)簽,修改 x2 的坐標(biāo)值來(lái)生成 y 軸的輔助線。這里有個(gè)需要注意的地方,在生成輔助線的時(shí)候要排除 y 軸的 0 值輔助線,因?yàn)樵撦o助線會(huì)和 x 軸重合。

 

js

復(fù)制代碼

// 這里我們可以巧妙使用y軸刻度,因?yàn)楸举|(zhì)就是line標(biāo)簽,修改x2的坐標(biāo)值即可 chart.selectAll(".y-axis .tick line").filter((d, i) => i > 0).attr("x2", svgWidth - margin.left - margin.right).attr("stroke", "#aaa").attr("stroke-width", .4);; chart.select(".y-axis path").style("display", "none");

隱藏柱子后,展示只有坐標(biāo)軸和輔助線的圖,我們可以很清楚地看到變化:

優(yōu)化后的效果圖如下:

新增旋轉(zhuǎn)標(biāo)簽

接著我們對(duì)圖表做些“裝飾”:每個(gè)柱子的底部文案怎么對(duì)齊呢?

我們可能會(huì)想到用 CSS 的定位做,但在這里 SVG 是不支持的,我們只能修改坐標(biāo)值,根據(jù)文案的字符長(zhǎng)度做偏移。同時(shí)這里要注意用 function 來(lái)獲取當(dāng)前的 this 上下文。通過(guò)?this.getBoundingClientRect().height?可以方便獲取寬度。

 

js

復(fù)制代碼

group.selectAll("text") .data(d => d.season) .enter() .append("text") .text((d, i) => { console.warn(d, i); return `${d.label}-${d.value}` }) .attr("x", d => columnWidth * (["Q1", "Q2", "Q3", "Q4"].indexOf(d.label) - 1) + 10) .attr("y", function (d) { const textHeight = this.getBoundingClientRect().height; // 獲取文本高度 return chartHeight + textHeight; // 加上一些偏移量,使文本位于 X 軸上方 }) .attr('fill', '#000') .attr("transform", (d, i) => { // 使用 transform 屬性旋轉(zhuǎn)文本 const x = columnWidth * (["Q1", "Q2", "Q3", "Q4"].indexOf(d.label) - 1); const y = chartHeight; return `rotate(270 ${x} ${y})`; // 在元素的中心點(diǎn)處旋轉(zhuǎn)90度 }).filter((d, i) => i === 0).attr('fill', '#fff')

效果如下:

最后,我們要再給圖表加一些交互效果。

交互效果:實(shí)現(xiàn) hover 展示每組的同季度柱子

示例代碼如下:

 

js

復(fù)制代碼

const rects = group // ... .on("mouseover", function (e) { const target = d3.select(e.target); const data = target.datum(); rects.filter((d) => d.label !== data.label).style("opacity", "0.2"); }) .on("mouseout", () => { rects.style("fill", (d, i) => colors[i]).style("opacity", "1"); });

這里我們只要監(jiān)聽鼠標(biāo)移入和移除的事件,然后通過(guò) DOM 獲取 D3 的選擇集,接著通過(guò) datum 獲取對(duì)應(yīng)的關(guān)聯(lián)的源數(shù)據(jù),最后過(guò)濾當(dāng)前移入的柱子,將其他的顏色設(shè)置透明。

為了過(guò)渡自然,我們還要處理設(shè)置每個(gè)柱子的過(guò)渡效果,添加 transition 屬性:

 

html

復(fù)制代碼

<style> rect { transition: all .2s linear; } </style>

最后調(diào)整后的效果:

交互效果:實(shí)現(xiàn)整組的 hover

示例代碼如下:

 

js

復(fù)制代碼

const groupItem = group .append("rect") .attr("x", (d) => columnWidth * ["Q1", "Q2", "Q3", "Q4"].indexOf(d.label)) .attr("y", 0) .attr("width", xScale.bandwidth()) .attr("height", (d) => chartHeight) .style("opacity", 0) .on("mouseover", function (e) { d3.select(this).style("fill", "blue").style("opacity", 0.05); }) .on("mouseout", function (e) { d3.select(this).style("fill", "blue").style("opacity", 0); });

看下這次實(shí)現(xiàn)后的效果:

交互效果:顯隱 tooltip

在做 tooltip 的 hover 的時(shí)候,我們需要在 SVG 的可繪制區(qū)域中監(jiān)聽鼠標(biāo)的移入和移出,但是直接在 SVG 是無(wú)法獲取數(shù)據(jù)值的,我們需要在組和柱子做監(jiān)聽,就可以獲得數(shù)據(jù)值和坐標(biāo)位置。這里先做個(gè)事件封裝,在內(nèi)部我們通過(guò) g 容器,然后在里面存入所有 SVG 元素。

注意,浮層的陰影我們可以用 CSS 的?filter: drop-shadow??文案的對(duì)齊我們使用?.attr("text-anchor", "end")?。

示例代碼如下:

 

js

復(fù)制代碼

/** * 監(jiān)聽浮層的位置 */ function onGroupLabel(e, d) { const mouseX = e.pageX; const mouseY = e.pageY; const labelOverlay = svg .append("g") .attr("class", "label-overlay") .attr("transform", `translate(${mouseX}, ${mouseY})`); labelOverlay .append("rect") .attr("x", 0) .attr("y", 0) .attr("rx", 5) .attr("ry", 5) .attr("width", 100) .attr("height", 120) .attr("fill", "#fff"); labelOverlay .append("text") .text(d.label) .attr("x", 10) .attr("y", 22) .attr("fill", "#aaa"); const seasons = labelOverlay .selectAll(".season") .data(d.season) .enter() .append("g") .attr("class", "season") .attr("transform", (d, i) => `translate(10, ${35 + i * 20})`); seasons .append("circle") .attr("cx", 5) .attr("cy", 5) .attr("r", 5) .style("fill", (d, i) => colors[i]); seasons .append("text") .text((d) => `${d.label}:`) .attr("x", 15) .attr("y", 9) .attr("fill", "black") .style("font-size", "12px"); seasons .append("text") .text((d) => `${d.value}`) .attr("x", 75) .attr("y", 9) .attr("text-anchor", "end") .attr("font-weight", "bold") .attr("fill", "black") .style("font-size", "12px"); svg.on("mousemove", function (e) { labelOverlay.attr("transform", `translate(${e.pageX}, ${e.pageY})`); }); } /** * 移除浮層的位置 */ function removeGroupLabel(e) { svg.selectAll(".label-overlay").remove(); svg.on("mousemove", null); }

在對(duì)應(yīng)的 SVG 元素做監(jiān)聽:

 

js

復(fù)制代碼

// 柱子 // ... .on("mouseover", function (e, d) { rects.filter((d1) => d1.label !== d.label).style("opacity", "0.2"); onGroupLabel(e, d3.select(this.parentNode).datum()); }) .on("mouseout", () => { rects.style("fill", (d, i) => colors[i]).style("opacity", "1"); removeGroupLabel(); }) // 分組 // ... .on("mouseover", function (e, d) { d3.select(this).style("fill", "blue").style("opacity", 0.05); onGroupLabel(e, d); }) .on("mouseout", function (e) { d3.select(this).style("fill", "blue").style("opacity", 0); removeGroupLabel(e); });

最終實(shí)現(xiàn)效果:

實(shí)現(xiàn)折線圖

當(dāng)我們有了柱狀圖的基礎(chǔ)后,接下來(lái)我們?cè)賮?lái)實(shí)現(xiàn)折線圖就簡(jiǎn)單很多了,這個(gè)時(shí)候我們能發(fā)現(xiàn)大量重復(fù)的代碼,而繪制折線的核心代碼只有一行:

 

js

復(fù)制代碼

// 1. 要繪制的數(shù)據(jù) // 2. 定義畫布大小和邊距 // 3. 創(chuàng)建SVG元素 // 4. 定義比例尺 // 5. 定義和添加X(jué)軸和Y軸 // 6. 繪制折線圖數(shù)據(jù) svg.append("path").datum(data).attr("fill", "none").attr("stroke", "steelblue").attr("d", d3.line().x(d => x(d.x)).y(d => y(d.y)));

效果如下:

實(shí)現(xiàn)動(dòng)態(tài)排序折線圖

該圖表難點(diǎn)在于動(dòng)畫遞進(jìn)效果、hover 展示效果,接下來(lái)我們就來(lái)實(shí)現(xiàn)這個(gè) ECharts 中相對(duì)復(fù)雜的動(dòng)態(tài)排序折線圖。

前置工作

首先定義我們的數(shù)據(jù)集,為了方便維護(hù),我們不會(huì)在 list 中定義大量的數(shù)組對(duì)象,因?yàn)檫@樣意味著大量重復(fù)無(wú)用的屬性,我們只需要用數(shù)組下標(biāo)定位 date、color、label 的值。

定義數(shù)據(jù)集:

 

js

復(fù)制代碼

// 生成一些假數(shù)據(jù) const data = { list: [ [ 5300, 6600, 6800, 6700, 6900, 7200, 7200, 7300, 7400, 8000, 7900, 8100, 8200, 10000, 10200, 10400, 10000, 9000, 11000, 10000, 10900, 12000, 12200, 12400, 12900, 13000, ], [ 5000, 6000, 6500, 6400, 5800, 9100, 15030, 15200, 15000, 17000, 18000, 16000, 15000, 15900, 17000, 18000, 16000, 12000, 17000, 16000, 15000, 14000, 13000, 12000, 12900, 19000, ], [ 5000, 6000, 6500, 6700, 6800, 10200, 15000, 15300, 15070, 17300, 18000, 17000, 17000, 17000, 22000, 22000, 21000, 24000, 25000, 23000, 22000, 22000, 25000, 25800, 28000, 40000, ], [ 6000, 6000, 6500, 6700, 6800, 10200, 15000, 15300, 15070, 17300, 18000, 17000, 17000, 17000, 22000, 22000, 21000, 24000, 25000, 33000, 33000, 22000, 25000, 55800, 58000, 60000, ], [ 6000, 6000, 6500, 6700, 6800, 10200, 15000, 15300, 15070, 17300, 18000, 17000, 17000, 17000, 55000, 55000, 51000, 54000, 55000, 53000, 52000, 22000, 45000, 45800, 50000, 56000, ], [ 6000, 6000, 6500, 6700, 6800, 10200, 15000, 15300, 15070, 17300, 18000, 17000, 17000, 17000, 22000, 44000, 41000, 44000, 45000, 43000, 42000, 33000, 35000, 35800, 38000, 40000, ], [ 5000, 6000, 6500, 6700, 6800, 10000, 25000, 25800, 25000, 37000, 38000, 37000, 47000, 47000, 48000, 59000, 59000, 59000, 67000, 66000, 65000, 64000, 73000, 72000, 72900, 73000, ], ], date: [ "1910", "1915", "1920", "1925", "1930", "1935", "1940", "1945", "1950", "1955", "1960", "1965", "1970", "1975", "1980", "1985", "1990", "1995", "2000", "2005", "2010", "2015", "2020", "2025", "2030", "2035", ], color: [ "#5470C6", "#91CC75", "#fac858", "#ee6666", "#73c0de", "#3ba272", "#9a60b4", ], label: ["Norwat", "France", "China", "Poland", "Russia", "Iceland", "US"], };

然后定義我們的繪制區(qū)域、坐標(biāo)軸以及樣式的優(yōu)化:

 

js

復(fù)制代碼

// 定義邊距、寬高 const margin = { top: 50, right: 50, bottom: 50, left: 50 } const width = 1000 - margin.left - margin.right const height = 600 - margin.top - margin.bottom // 將日期字符串轉(zhuǎn)化為日期對(duì)象 const parseDate = d3.timeParse('%Y') data.date = data.date.map(d => parseDate(d)) // 定義x軸比例尺 const x = d3.scaleTime() .range([0, width]) .domain(d3.extent(data.date)) // 定義y軸比例尺 const y = d3.scaleLinear() .range([height, 0]) .domain([0, d3.max(data.list.flat().map(d => d))]) // 在SVG中添加g元素并設(shè)置transform,來(lái)讓g元素居中顯示 const svg = d3.select('svg') .attr('width', width + margin.left + margin.right) .attr('height', height + margin.top + margin.bottom) const g = svg.append('g') .attr('transform', `translate(${margin.left},${margin.top})`) // 添加x軸及其標(biāo)簽 g.append('g') .call(d3.axisBottom(x)) .attr("class", "x-axis") .style("color", '#aaa') .attr('transform', `translate(0,${height})`) // 添加y軸及其標(biāo)簽 g.append('g') .attr("class", "y-axis") .style("color", '#aaa') .call(d3.axisLeft(y).ticks(5)) g.selectAll(".y-axis .tick line").filter((d, i) => i > 0).attr("x2", width).attr("stroke", "#aaa").attr("stroke-width", .4); g.select(".y-axis path").style("display", "none");

接著我們需要繪制線段。

根據(jù) data 生成path路徑

在繪制每組時(shí),我們 selectAll 就可以根據(jù) data 傳入的數(shù)組長(zhǎng)度生成不同的分組,不用考慮數(shù)據(jù)的傳入,這里的x(data.date[i])??y(d)?分別代表了折線圖中的每個(gè)數(shù)據(jù)點(diǎn)的橫坐標(biāo)和縱坐標(biāo)。

由于 x 軸的比例尺定義了時(shí)間軸上的位置,所以根據(jù)每個(gè)數(shù)據(jù)點(diǎn)對(duì)應(yīng)的時(shí)間,可以通過(guò) x 比例尺來(lái)確定其橫坐標(biāo)。而 y 軸的比例尺定義了數(shù)據(jù)值的范圍,所以根據(jù)每個(gè)數(shù)據(jù)點(diǎn)的數(shù)值,可以通過(guò) y 比例尺來(lái)確定其縱坐標(biāo)。

代碼如下:

 

js

復(fù)制代碼

// 定義生成折線的函數(shù) const lineGenerator = d3.line() .x((d, i) => x(data.date[i])) .y(d => y(d)) .defined(d => d !== null) // 防止缺少數(shù)據(jù)導(dǎo)致折線斷裂 const group = g.selectAll('.group').data(data.list).enter().append('g').attr("class", "group") const lines = group.append('path') .datum(d => d) .attr('class', 'line') .attr('d', lineGenerator) .attr('stroke', (d, i) => data.color[i]) .attr('stroke-width', '2') .attr('fill', 'none')

效果如下:

接著我們開始繪制折線圖的動(dòng)態(tài)效果:

 

js

復(fù)制代碼

// 綁定過(guò)渡方法和動(dòng)畫效果 lines.attr('stroke-dasharray', function () { return `${this.getTotalLength()} ${this.getTotalLength()}` }) .attr('stroke-dashoffset', function () { return this.getTotalLength() }) .transition() .ease(d3.easeLinear) // 過(guò)渡效果 .delay(500) .duration(1000) .attr('stroke-dashoffset', 0)

stroke-dasharray?和?stroke-dashoffset?是 SVG 中用來(lái)定義路徑線段樣式的兩個(gè)屬性。

  • stroke-dasharray?屬性定義了對(duì)虛線的描述。例如,如果設(shè)置?stroke-dasharray: 5 5,則表示在路徑中每 5 個(gè)像素繪制一個(gè)實(shí)線,然后 5 個(gè)像素留空,然后再 5 個(gè)像素繪制一個(gè)實(shí)線……如此反復(fù)。

  • stroke-dashoffset?屬性定義了虛線的起始位置,也就是虛線距離路徑起始點(diǎn)的偏移量。例如,如果設(shè)置?stroke-dashoffset: 5,則表示路徑虛線的起始點(diǎn)向路徑起始點(diǎn)相對(duì)偏移 5 個(gè)像素。

在上面的代碼中,首先通過(guò)獲取?getTotalLength()?方法獲取路徑總長(zhǎng)度,然后將?stroke-dasharray?屬性設(shè)為該長(zhǎng)度值的兩倍,因此實(shí)現(xiàn)了完全隱藏路徑線段的效果。接下來(lái)通過(guò)設(shè)置?stroke-dashoffset?的初始值為總長(zhǎng)度值,實(shí)現(xiàn)了路徑從一開始完全隱藏的效果。最后通過(guò)過(guò)渡效果和延遲設(shè)置,使得路徑從隱藏狀態(tài)逐漸展示出來(lái),從而實(shí)現(xiàn)了路徑動(dòng)畫效果。

效果如下:

最后,我們完善交互細(xì)節(jié)。

交互效果:文字跟隨路徑動(dòng)畫

首先創(chuàng)建了一個(gè)?textPath?元素,并將其添加到每個(gè)組中的?text?元素中。我們使用 xlink:href 屬性將?textPath?元素與相應(yīng)的折線路徑進(jìn)行關(guān)聯(lián),并使用?startOffset?屬性設(shè)置文字的起始位置在線的端頭右側(cè)。然后,我們?cè)趧?dòng)畫過(guò)渡中,通過(guò)修改?startOffset?屬性的值,將文字從線的端頭右側(cè)移動(dòng)到線的起始位置,實(shí)現(xiàn)文字的展示效果。

代碼如下:

 

js

復(fù)制代碼

// ... const textPaths = group .append("text") .append("textPath") .attr("xlink:href", (d, i) => `#line-path-${i}`) .attr("startOffset", "100%") .attr("text-anchor", "end") .attr("fill", (d, i) => data.color[i]) .text((d, i) => data.label[i]); // 綁定過(guò)渡方法和動(dòng)畫效果 lines .attr("stroke-dasharray", function () { return `${this.getTotalLength()} ${this.getTotalLength()}`; }) .attr("stroke-dashoffset", function () { return this.getTotalLength(); }) .transition() .ease(d3.easeLinear) // 過(guò)渡效果 .delay(0) .duration(6000) .attr("stroke-dashoffset", 0); textPaths .attr("startOffset", "0%") .attr("text-anchor", "end") .transition() .ease(d3.easeLinear) .delay(0) .duration(6000) .attr("startOffset", "100%");

效果如下:

交互效果:插值計(jì)算文案位置

上文的文字跟隨路徑動(dòng)畫方法明顯的缺陷就是文案是垂直于折線的,很顯然不滿足我們的需求,要想讓文案在線端頭的右側(cè)移動(dòng),其實(shí)我們只要得到每個(gè)線的端頭的 y 坐標(biāo)即可。

我們獲取 lines,并 each 遍歷每個(gè)元素,篩選對(duì)應(yīng)的 text,接著獲取 dom 節(jié)點(diǎn),通過(guò) getTotalLength 能得到路徑的長(zhǎng)度。然后生成?interpolator, 用于創(chuàng)建一個(gè)在 0 和路徑長(zhǎng)度之間進(jìn)行插值函數(shù),用于動(dòng)態(tài)計(jì)算路徑上不同點(diǎn)的位置,從而實(shí)現(xiàn)路徑繪制的動(dòng)畫效果。

實(shí)現(xiàn)思路我們有了,接下來(lái)我們只要監(jiān)聽line的tween方法的end事件,也就是能得到當(dāng)前繪制的線的位置,位置范圍是 0 到 1,而得到的 t 代表動(dòng)畫的進(jìn)度,我們知道 interpolator 又是一個(gè)插值函數(shù),那么對(duì)應(yīng)能得到實(shí)際的長(zhǎng)度了,然后通過(guò) svg 的 getPointAtLength 就能獲取對(duì)應(yīng)的 point 坐標(biāo)了。接下來(lái)修改下 text 節(jié)點(diǎn)的位置即可。

代碼如下:

 

js

復(fù)制代碼

const texts = d3.selectAll(".a-txt"); // 選擇所有文本元素 lines.each(function (d, i) { const line = d3.select(this); // 當(dāng)前折線元素 const text = texts.filter(function (_, j) { return j === i; // 根據(jù)索引篩選對(duì)應(yīng)的文本元素 }); const pathEl = line.node(); //獲取dom節(jié)點(diǎn) const pathLength = pathEl.getTotalLength(); const interpolator = d3.interpolate(0, pathLength); line .attr("stroke-dasharray", `${pathLength} ${pathLength}`) .attr("stroke-dashoffset", pathLength) .transition() .ease(d3.easeLinear) .delay(0) .duration(6000) .attr("stroke-dashoffset", 0) .tween("end", function () { return function (t) { const length = interpolator(t); const point = pathEl.getPointAtLength(length); const x = point.x; const y = point.y; text .text(data.label[i]) .attr("x", x + 10) .attr("y", y); // 將位置應(yīng)用到對(duì)應(yīng)的文本元素 }; }); });

實(shí)現(xiàn)效果如下:

交互效果:輔助線、鼠標(biāo)定位線的每個(gè)點(diǎn)并展示 Tooltip

我們?cè)?SVG 監(jiān)聽鼠標(biāo)移動(dòng)的事件后,根據(jù) mouseX 就可以得到索引的位置,通過(guò)這個(gè)索引我們可以獲取到 data 里的任一數(shù)據(jù),接著我們就可以繪制輔助線和浮層,而浮層的具體實(shí)現(xiàn)跟折線圖類似,我們稍作修改即可。

繪制輔助線和浮層

代碼如下:

 

javascript

復(fù)制代碼

svg .on("mousemove", function (event) { const mouseX = d3.pointer(event)[0]; const mouseY = d3.pointer(event)[1]; const year = new Date(x.invert(mouseX - margin.left)).getFullYear(); // 更新輔助虛線的位置和顯示狀態(tài) if (year >= 1997 && year <= 2022) { // 獲取索引位置 let id = data.date.findIndex((item) => { return new Date(item).getFullYear() === year; }); helperLine .attr("x1", x(data.date[id])) .attr("y1", 0) .attr("x2", x(data.date[id])) .attr("y2", height) .style("opacity", 1); // 更新浮層位置 labelOverlay.attr( "transform", `translate(${mouseX > width - 150 ? width - 150 : mouseX + 10}, ${ mouseY > height - 180 ? height - 180 : mouseY + 10 })` ); d3.select(".label-rect").style("display", "block"); d3.select(".over-year").text(year); // 繪制label,和之前的折線圖的label相似 initLabel(id); } })

繪制垂直輔助線 helperLine,我們只要 selectAll 和 join 創(chuàng)建元素后,由于是 group,我們?cè)?data 的 d 中獲取到的是 list 的某一項(xiàng),這個(gè)時(shí)候傳入索引我們就得到 y 軸的值。我們知道通過(guò) y 軸比例尺和 y 軸的數(shù)據(jù)值,就可以通過(guò) D3 的比例尺方法得到 y 軸的坐標(biāo)值,而 mouseX 我們是知道的,所以接著我們就可以繪制相交點(diǎn)的圓形了。

繪制相交點(diǎn)圓形
 

javascript

復(fù)制代碼

const cs = group .selectAll(".circle") .data((d) => { return [d[id]]; }) .join("circle") .attr("class", "circle") .attr("cx", (d, i) => x(data.date[id])) .attr("cy", (d, i) => y(d)) .attr("r", 5); let i = -1; cs.each(function () { const dom = d3.select(this); i++; dom.attr("fill", data.color[i]); });

事件的優(yōu)化

我們要注意這些 hover 的元素,在鼠標(biāo)超出繪圖區(qū)域,要通過(guò) mouseout 移除浮層,但是在 svg 內(nèi)部鼠標(biāo)一旦移動(dòng)到線段或文字等,也會(huì)觸發(fā) mouseout 就會(huì)誤刪。我們可以根據(jù) class 類名做區(qū)分,但是后續(xù)新增 svg 節(jié)點(diǎn)后是很難維護(hù)的,所以是否移除輔助線、相交圓點(diǎn)、tooltip,我們通過(guò)鼠標(biāo)是否超出繪圖區(qū)域判斷。

在進(jìn)入 mousenter 的時(shí)候我們需要?jiǎng)?chuàng)建 svg 元素,在 mousemove 的時(shí)候我們要做更新節(jié)點(diǎn)的操作,在鼠標(biāo)超出繪圖區(qū)域的時(shí)候移除 hover 元素。

具體代碼如下:

 

js

復(fù)制代碼

.on("mouseenter", (e) => { // 創(chuàng)建浮層元素 labelOverlay = svg.append("g").attr("class", "label-overlay"); // 繪制元素 labelOverlay .append("rect") .attr("class", "label-rect") .attr("x", 0) .attr("y", 0) .attr("rx", 5) .attr("ry", 5) .attr("width", 150) .attr("height", 180) .style("display", "none") .attr("fill", "#fff"); labelOverlay .append("text") .attr("class", "over-year") .attr("x", 10) .attr("y", 22) .attr("fill", "#aaa"); }) .on("mouseout", function (e) { const mouseX = e.pageX; const mouseY = e.pageY; const chartX = svg.node().getBoundingClientRect().x; const chartY = svg.node().getBoundingClientRect().y; const chartWidth = svg.node().getBoundingClientRect().width; const chartHeight = svg.node().getBoundingClientRect().height; if ( mouseX < chartX || mouseX > chartX + chartWidth || mouseY < chartY || mouseY > chartY + chartHeight ) { svg.selectAll(".label-overlay").remove(); } });

效果如下:

總結(jié)

最后,我們總結(jié)下這一節(jié)的關(guān)鍵知識(shí)點(diǎn)。

  1. 為什么要用 D3:?D3 基于 SVG 的數(shù)據(jù)驅(qū)動(dòng)視圖的庫(kù),通過(guò)鏈?zhǔn)秸{(diào)用、封裝比例尺、數(shù)學(xué)方法、數(shù)據(jù)狀態(tài)的管理等,我們可以輕松繪制復(fù)雜的圖表。

  2. 如何理解數(shù)據(jù)驅(qū)動(dòng)視圖:?我們的關(guān)注點(diǎn)只在數(shù)據(jù),不用深入數(shù)據(jù)背后的調(diào)用,修改數(shù)據(jù)意味著視圖會(huì)被更新。

  3. 如何實(shí)現(xiàn)柱狀圖:?定義繪圖區(qū)域 -> scaleBand 用于離散數(shù)據(jù),用在 x 軸的比例尺;在 y 軸我們用scaleLinear,生成比例尺 -> 生成坐標(biāo)軸 -> 通過(guò) rect 生成柱體。

  4. 實(shí)現(xiàn)多層級(jí)旋轉(zhuǎn)標(biāo)簽柱狀圖的難點(diǎn):?多層級(jí)我們要考慮好數(shù)據(jù)結(jié)構(gòu),也就是數(shù)組嵌套數(shù)組,在交互難點(diǎn)部分,通過(guò)在內(nèi)部元素的 hover,傳入 d、e,我們能創(chuàng)建 label,實(shí)際操作中我們很有可能遇到其他元素導(dǎo)致 mouseout,我們可以通過(guò)dom.style("pointer-events", "none")?或者監(jiān)聽元素位置判斷是否選中來(lái)解決 label 的誤刪。是否高亮的實(shí)現(xiàn)我們只要在對(duì)應(yīng)的元素監(jiān)聽事件即可。

  5. 如何實(shí)現(xiàn)折線圖:?定義繪圖區(qū)域 -> scaleTime 用于時(shí)間數(shù)據(jù),用在 x 軸的比例尺;在 y 軸我們用 scaleLinear,生成比例尺 -> 生成坐標(biāo)軸 -> 通過(guò) path 生成折線。

  6. 實(shí)現(xiàn)動(dòng)態(tài)排序折線圖的難點(diǎn):

    • 線的動(dòng)畫實(shí)現(xiàn):我們通過(guò)?stroke-dasharray?來(lái)定義實(shí)線和虛線的長(zhǎng)度,通過(guò)修改?stroke-dashoffset?來(lái)實(shí)現(xiàn)移動(dòng),同時(shí)應(yīng)用 transition 過(guò)渡即可;
    • 實(shí)現(xiàn)文字跟隨動(dòng)畫:我們只要監(jiān)聽 SVG 的 mouseX,通過(guò)插值轉(zhuǎn)換器 interpolator,傳入 tween 方法的 end 事件中回調(diào)的 t 得到對(duì)應(yīng)的進(jìn)度值,我們就可以得到實(shí)際線段的長(zhǎng)度,最后通過(guò) svg 的?getPointAtLength?方法就可以得到 point 坐標(biāo),更新 text 的 x 和 y 的屬性即可。

下一節(jié)我們將繼續(xù)實(shí)現(xiàn)高級(jí)圖表——雷達(dá)圖和餅圖。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-848168.html

到了這里,關(guān)于前端可視化入門與實(shí)戰(zhàn):D3 高級(jí)圖表實(shí)戰(zhàn):柱狀圖、折線圖的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【Python入門系列】第十五篇:Python數(shù)據(jù)可視化和圖表繪制

    數(shù)據(jù)可視化是數(shù)據(jù)分析和數(shù)據(jù)科學(xué)中非常重要的一部分。通過(guò)可視化,我們可以更好地理解數(shù)據(jù)、發(fā)現(xiàn)數(shù)據(jù)之間的關(guān)系、展示數(shù)據(jù)的趨勢(shì)和模式,并向他人傳達(dá)我們的發(fā)現(xiàn)。 Python是一種功能強(qiáng)大的編程語(yǔ)言,擁有許多用于數(shù)據(jù)可視化的庫(kù)和工具。其中,Matplotlib是最常用的繪

    2024年02月13日
    瀏覽(27)
  • [小塵送書-第二期]《Power BI數(shù)據(jù)分析與可視化實(shí)戰(zhàn)》數(shù)據(jù)清洗、數(shù)據(jù)建模、數(shù)據(jù)可視化設(shè)計(jì)與高級(jí)技法

    [小塵送書-第二期]《Power BI數(shù)據(jù)分析與可視化實(shí)戰(zhàn)》數(shù)據(jù)清洗、數(shù)據(jù)建模、數(shù)據(jù)可視化設(shè)計(jì)與高級(jí)技法

    大家好,我是小塵,歡迎你的關(guān)注!大家可以一起交流學(xué)習(xí)!歡迎大家在CSDN后臺(tái)私信我!一起討論學(xué)習(xí),討論如何找到滿意的工作! ?????博主主頁(yè):小塵要自信 ?????推薦專欄: ?????《1》開發(fā)環(huán)境配置攻略 ?????《2》Java程序員的成長(zhǎng) ?????《3》2023Java面試實(shí)

    2024年02月13日
    瀏覽(30)
  • 尚硅谷Docker實(shí)戰(zhàn)教程-筆記13【高級(jí)篇,Docker輕量級(jí)可視化工具Portainer】

    尚硅谷Docker實(shí)戰(zhàn)教程-筆記13【高級(jí)篇,Docker輕量級(jí)可視化工具Portainer】

    尚硅谷大數(shù)據(jù)技術(shù)-教程-學(xué)習(xí)路線-筆記匯總表【課程資料下載】 視頻地址:尚硅谷Docker實(shí)戰(zhàn)教程(docker教程天花板)_嗶哩嗶哩_bilibili 尚硅谷Docker實(shí)戰(zhàn)教程-筆記01【基礎(chǔ)篇,Docker理念簡(jiǎn)介、官網(wǎng)介紹、平臺(tái)入門圖解、平臺(tái)架構(gòu)圖解】 尚硅谷Docker實(shí)戰(zhàn)教程-筆記02【基礎(chǔ)篇,Do

    2024年02月15日
    瀏覽(118)
  • 可視化爬蟲框架spiderflow入門及實(shí)戰(zhàn)

    可視化爬蟲框架spiderflow入門及實(shí)戰(zhàn)

    官網(wǎng): 點(diǎn)擊直達(dá)官網(wǎng) 文檔: 點(diǎn)擊查看官網(wǎng)文檔 說(shuō)明: 目前官網(wǎng)和文檔均無(wú)法正常訪問(wèn),原因未知,參考本文即可。再有問(wèn)題歡迎留言討論。 以下內(nèi)容部分來(lái)自官網(wǎng)或官網(wǎng)文檔。文章比較長(zhǎng),請(qǐng)準(zhǔn)備好瓜子和小板凳~~~ TIP: 文中用到的網(wǎng)站地址僅為了說(shuō)明功能,如有侵犯,請(qǐng)告

    2024年02月04日
    瀏覽(12)
  • 小程序數(shù)據(jù)可視化:使用圖表和可視化工具展示數(shù)據(jù)

    小程序數(shù)據(jù)可視化:使用圖表和可視化工具展示數(shù)據(jù)

    在當(dāng)今信息爆炸的時(shí)代,數(shù)據(jù)無(wú)疑是最珍貴的資源之一。然而,海量的數(shù)據(jù)如果不加以整理和展示,很難從中獲取有價(jià)值的信息。這時(shí)候,數(shù)據(jù)可視化就發(fā)揮了重要作用,它能夠通過(guò)圖表和可視化工具將復(fù)雜的數(shù)據(jù)轉(zhuǎn)化為直觀的視覺(jué)形式,幫助人們更好地理解和分析數(shù)據(jù)。本

    2024年02月11日
    瀏覽(39)
  • 數(shù)據(jù)可視化:圖表繪制詳解

    數(shù)據(jù)可視化是一種將抽象的數(shù)字和數(shù)據(jù)轉(zhuǎn)化為直觀圖形的技術(shù),使數(shù)據(jù)的模式、趨勢(shì)和關(guān)系一目了然。本文將詳細(xì)介紹如何繪制各種類型的圖表,包括柱狀圖、折線圖、餅圖、散點(diǎn)圖和熱力圖等。 第一部分:圖表類型和選擇 1. 柱狀圖 柱狀圖是用于比較類別數(shù)據(jù)的常見(jiàn)圖表。

    2024年02月12日
    瀏覽(34)
  • Excel 動(dòng)態(tài)可視化圖表分享

    Excel 動(dòng)態(tài)可視化圖表分享

    AIGC ChatGPT 職場(chǎng)案例 AI 繪畫 與 短視頻制作 PowerBI 商業(yè)智能 68集 數(shù)據(jù)庫(kù)Mysql 8.0 ?54集 數(shù)據(jù)庫(kù)Oracle 21C 142集 Office 2021實(shí)戰(zhàn)應(yīng)用 Python 數(shù)據(jù)分析實(shí)戰(zhàn), ETL Informatica 數(shù)據(jù)倉(cāng)庫(kù)案例實(shí)戰(zhàn) Excel 2021實(shí)操 100集, Excel 2021函數(shù)大全 80集 Excel 2021高級(jí)圖表應(yīng)用89集, Excel 2021大屏可視化制作 56集

    2024年01月18日
    瀏覽(30)
  • ChatGPT 隨機(jī)動(dòng)態(tài)可視化圖表分析

    ChatGPT 隨機(jī)動(dòng)態(tài)可視化圖表分析

    動(dòng)態(tài)可視化圖表分析實(shí)例如下圖: ? ?這樣的動(dòng)態(tài)可視化圖表可以使用ChatGPT OpenAI?來(lái)實(shí)現(xiàn)。 ?給ChatGPT發(fā)送指令: 你現(xiàn)在是一個(gè)數(shù)據(jù)分析師,請(qǐng)使用HTML,JS,Echarts,來(lái)完成一個(gè)動(dòng)態(tài)條形圖,條形圖方向橫向,數(shù)據(jù)可以隨機(jī)生成,并且隨機(jī)生成10個(gè)不同的商品名稱,每個(gè)類別分

    2024年02月11日
    瀏覽(25)
  • 數(shù)據(jù)可視化(七)常用圖表的繪制

    數(shù)據(jù)可視化(七)常用圖表的繪制

    1. 2. ? 3. ? 4. ? ? ? ? ? ? ?

    2024年02月14日
    瀏覽(43)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包