绘制散点图
<h3>函数定义和输入参数</h3>
<pre><code>scattergram(data, imgWidth, imgHeight) {</code></pre>
<p>scattergram 函数接受三个参数:</p>
<ul>
<li>data:包含散点图数据的对象。</li>
<li>imgWidth 和 imgHeight:图像的宽度和高度,用于设置绘图区域的尺寸。</li>
</ul>
<h3>初始化变量和数据处理</h3>
<pre><code>const canvasWidth = this.vm.imageWidth;
const canvasHeight = this.vm.imageHeight;
const location = data.data.vector;
const type_vec = data.data.type_vec || [];
const points = [];
let umin = location[0] || 0;
let umax = location[0] || 0;
let vmin = location[1] || 0;
let vmax = location[1] || 0;
let count = 0;</code></pre>
<ul>
<li>canvasWidth 和 canvasHeight:从 this.vm 对象中获取图像的宽度和高度。</li>
<li>location:从 data.data.vector 中获取包含点坐标的数组。</li>
<li>type_vec:从 data.data.type_vec 中获取点的类型数组,默认为空数组。</li>
<li>points:存储筛选后的点数据。</li>
<li>umin, umax, vmin, vmax:用于记录数据中 u 和 v 坐标的最小值和最大值。</li>
<li>count:用于跟踪当前点的索引。</li>
</ul>
<h3>处理数据点</h3>
<pre><code>for (let index = 0; index &lt; location.length; index += 3) {
const u = location[index];
const v = location[index + 1];
const w = location[index + 2];
if (isNaN(u) || isNaN(v) || isNaN(w)) {
count++;
continue;
}
if (type_vec) {
if (type_vec[count] &lt;= 0) {
count++;
continue;
}
}
count++;
if (u &gt; umax) umax = u;
if (u &lt; umin) umin = u;
if (v &gt; vmax) vmax = v;
if (v &lt; vmin) vmin = v;
points.push([u, v, w]);
}</code></pre>
<ul>
<li>遍历 location 数组中的每个点(每三个值代表一个点的 u, v, w 坐标)。</li>
<li>如果点的坐标值不是数字,则跳过该点。</li>
<li>如果 type_vec 存在,并且对应的类型值小于等于0,则跳过该点。</li>
<li>更新 u 和 v 的最小值和最大值。</li>
<li>将有效的点([u, v, w])添加到 points 数组中。</li>
</ul>
<h3>设置比例尺</h3>
<pre><code>const x = this.xScale = d3.scaleLinear()
.domain([umin, umax])
.range([30, canvasWidth - 30]);
const y = this.yScale = d3.scaleLinear()
.domain([vmin, vmax])
.range([30, canvasHeight - 30]);</code></pre>
<ul>
<li>使用 D3 的 scaleLinear 方法创建 x 轴和 y 轴的线性比例尺。</li>
<li>domain 定义了数据的范围(最小值到最大值)。</li>
<li>range 定义了绘图区域的范围(30 到 canvas 的宽度或高度减去 30)。</li>
</ul>
<h3>绘制点</h3>
<pre><code>this.g.append('g')
.attr('class', 'dot')
.attr('fill-opacity', 1)
.style('pointer-events', 'none')
.selectAll('circle')
.data(points)
.enter().append('circle')
.attr('u', d =&gt; d[0])
.attr('v', d =&gt; d[1])
.attr('w', d =&gt; d[2])
.attr('transform', function (d) {
return `translate(${x(d[0])},${y(d[1])})`;
})
.attr('fill', 'red')
.attr('r', () =&gt; {
if (points.length &gt; 1000) {
return 0.5;
} else if (points.length &lt;= 1000 &amp;&amp; points.length &gt; 500) {
return 1;
} else if (points.length &lt;= 500 &amp;&amp; points.length &gt; 100) {
return 1.5;
} else {
return 2;
}
});</code></pre>
<ul>
<li>向 this.g 元素中添加一个新的 <g> 元素用于容纳点。</li>
<li>选择所有 <circle> 元素,绑定 points 数据,并对每个点添加一个 <circle> 元素。</li>
<li>设置每个圆的位置(通过 transform 属性)。</li>
<li>根据点的数量设置不同的圆半径。</li>
</ul>
<h3>添加坐标轴</h3>
<pre><code>const axisBottom = d3.axisBottom(x);
const axisLeft = d3.axisLeft(y);
// 添加x轴
const axixXg = this.g
.append('g')
.style('pointer-events', 'none')
.attr('class', 'axis-x').call(axisBottom)
.attr('font-size', 12)
.attr('transform', `translate(0,${canvasHeight - 30})`)
const axixYg = this.g
.append('g')
.style('pointer-events', 'none')
.attr('class', 'axis-y').call(axisLeft)
.attr('font-size', 12)
.attr('transform', 'translate(30,0)')</code></pre>
<ul>
<li>使用 D3 的 axisBottom 和 axisLeft 方法创建 x 轴和 y 轴。</li>
<li>将这些轴添加到 this.g 元素中,并设置适当的变换属性来定位轴。</li>
</ul>
<h3>添加坐标轴标签</h3>
<pre><code>axixXg.append('text')
.attr('x', canvasWidth - 80)
.attr('y', 25)
.attr('dx', 40)
.attr('dy', 10)
.attr('text-anchor', 'middle')
.attr('fill', '#fff')
.attr('font-size', 12)
.text('U值');
axixYg.append('text')
.attr('x', 0)
.attr('y', 40)
.attr('dx', -20)
.attr('dy', -20)
.attr('text-anchor', 'middle')
.attr('fill', '#fff')
.attr('font-size', 12)
.text('V值');</code></pre>
<p>向 x 轴和 y 轴添加文本标签,分别为 "U值" 和 "V值"。</p>
<p>这段代码用于创建一个散点图,处理数据、设置坐标轴和比例尺,并在图中绘制点。</p>
<p>完整代码:</p>
<pre><code class="language-javascript"> scattergram(data, imgWdith, imgHeight) {
const canvasWidth = this.vm.imageWidth;
const canvasHeight = this.vm.imageHeight;
const location = data.data.vector;
const type_vec = data.data.type_vec || [];
const points = [];
let umin = location[0] || 0;
let umax = location[0] || 0;
let vmin = location[1] || 0;
let vmax = location[1] || 0;
let count = 0;
for (let index = 0; index &lt; location.length; index += 3) {
const u = location[index];
const v = location[index + 1];
const w = location[index + 2];
if (isNaN(u) || isNaN(v) || isNaN(w)) {
count++;
continue;
}
if (type_vec) {
if (type_vec[count] &lt;= 0) {
count++;
continue;
}
}
count++;
if (u &gt; umax) umax = u;
if (u &lt; umin) umin = u;
if (v &gt; vmax) vmax = v;
if (v &lt; vmin) vmin = v;
points.push([u, v, w]);
}
this.allPoints = points;
const x = this.xScale = d3.scaleLinear()
.domain([umin, umax])
.range([30, canvasWidth - 30]);
const y = this.yScale = d3.scaleLinear()
.domain([vmin, vmax])
.range([30, canvasHeight - 30]);
this.g.append('g')
.attr('class', 'dot')
.attr('fill-opacity', 1)
.style('pointer-events', 'none')
.selectAll('circle')
.data(points)
.enter().append('circle')
.attr('u', d =&gt; d[0])
.attr('v', d =&gt; d[1])
.attr('w', d =&gt; d[2])
.attr('transform', function (d) {
return `translate(${x(d[0])},${y(d[1])})`;
})
.attr('fill', 'red')
.attr('r', () =&gt; {
if (points.length &gt; 1000) {
return 0.5;
} else if (points.length &lt;= 1000 &amp;&amp; points.length &gt; 500) {
return 1;
} else if (points.length &lt;= 500 &amp;&amp; points.length &gt; 100) {
return 1.5;
} else {
return 2;
}
});
const axisBottom = d3.axisBottom(x);
const axisLeft = d3.axisLeft(y);
// 添加x轴
const axixXg = this.g
.append('g')
.style('pointer-events', 'none')
.attr('class', 'axis-x').call(axisBottom)
.attr('font-size', 12)
.attr('transform', `translate(0,${canvasHeight - 30})`)
const axixYg = this.g
.append('g')
.style('pointer-events', 'none')
.attr('class', 'axis-y').call(axisLeft)
.attr('font-size', 12)
.attr('transform', 'translate(30,0)')
axixXg.append('text')
.attr('x', canvasWidth - 80)
.attr('y', 25)
.attr('dx', 40)
.attr('dy', 10)
.attr('text-anchor', 'middle')
.attr('fill', '#fff')
.attr('font-size', 12)
.text('U值');
axixYg.append('text')
.attr('x', 0)
.attr('y', 40)
.attr('dx', -20)
.attr('dy', -20)
.attr('text-anchor', 'middle')
.attr('fill', '#fff')
.attr('font-size', 12)
.text('V值');
}</code></pre>