Learning D3.js(3) 散点图与axis

本文通过实战演示如何使用 D3.js 创建动态散点图,并添加坐标轴,运用 transition 实现平滑过渡效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

不同于前面的两个教程,今天的教程是我自己写的,算是复习教程,复习一下之前学到的transition变换效果,及d3.scale.linear(),domain(),range()几个方法。

不过我们会使用一个新的api:axis

demo

http://www.d3js.cn/demo/bar7.html

http://www.d3js.cn/demo/bar8.html

首先这是一个散点图 那么我们需要在绘制的时候,使用svg的circle标签绘制圆形。

<svg width="50" height="50">
<circle cx="25" cy="25" r="25" fill="purple" />
</svg>

注意circle标签的属性 cx表示圆心横坐标,cy表示圆心纵坐标,r表示圆心半径

我们的数据是这样的

    var dataset = [
        [5, 20,1], [480, 90,2], [250, 50,3], [100, 33,4], [330, 95,5],
        [410, 12,6], [475, 44,7], [25, 67,8], [85, 21,9], [220, 88,10],
        [600, 150,11]
    ];

首先仍然要建立一个容器

    //Width and height
    var w = 600;
    var h = 400;
    var padding = 20;
    var chart = d3.select("body")
            .append("svg")
            .attr("width", w)
            .attr("height", h);

之后呢,利用d3.scale.linear(),配合domain数据,及range范围,规定图表内点的属性。

    var xScale = d3.scale.linear()
            .domain([0, d3.max(dataset, function(d) { return d[0]; })])
            .range([padding, w - padding * 2]);//x轴

    var yScale = d3.scale.linear()
            .domain([0, d3.max(dataset, function(d) { return d[1]; })])
            .range([h - padding, padding]);//y轴

    var rScale = d3.scale.linear()
            .domain([0, d3.max(dataset, function(d) { return d[1]; })])
            .range([5, 15]);//半径,5-15

利用selectAll配合data方法切分图表

    chart.selectAll("circle")
            .data(dataset)
            .enter()
            .append('circle')
            .attr("cx", function(d) {
                return xScale(d[0]);
            })
            .attr("cy", function(d) {
                return yScale(d[1]);
            })
            .attr("r", function(d) {
                return rScale(d[1]);
            });

这时候,横坐标就是我们数据中数组第一项,而纵坐标就是第二项,半径在这里为了方便,使用第二项作为基准。

这样图表的效果基本ok

快照3

然后我们让图表动起来。

    setInterval(function(){
        dataset.push(dataset.shift())
        redraw()
    },1000)

利用setInterval计时器,更新数据,每隔一秒,把数据的第一项扔到最后,之后redraw则是重绘图表的过程。

    function redraw() {
        chart.selectAll("circle")
                .data(dataset)
                .transition()
                .duration(1000)
                .attr("cy", function(d) {
                    return yScale(d[1]);
                })
                .attr("r", function(d) {
                    return rScale(d[1]);
                })
    }

那么第一个demo就ok了 http://www.d3js.cn/demo/bar7.html

这样的图表太单调了,没有横轴纵轴的标识。之前我们使用line标签来画线,而d3.js提供了方便的api来绘制这类坐标轴。

一般比较常用的是 axis.scale([scale])与axis.orient([orientation])两个方法。

前者与d3.scale.linear类似,可以绑定数据,而后者可以规定轴的方向(横轴或者纵轴)。当用户的值设置为top或者bottom时,为水平轴,而left或者right时,为垂直轴。

axis生成后,包括line或者path标签,还有text标签,可以方便应用样式。

使用axis时一般这样用:

    var xAxis = d3.svg.axis()
            .scale(xScale)
            .orient("bottom").ticks(5)//首先定义一个轴。tick跟之前讲过的tick类似,是规定刻度的间隔数

chart.append("g")//创建axis的区域
    .attr("transform", "translate(0,30)")//进行位移
    .call(axis)//绑定预先定义好的axis

先定义一个轴,再用call方法绑定这个轴

这样我们给之前的图表加上横轴纵轴

    //Define x axis
    var xAxis = d3.svg.axis()
            .scale(xScale)
            .orient("bottom").ticks(5)

    //Create x axis
    chart.append("g")
            .attr("class", "axis")
            .attr("transform", "translate(0," + (h - padding) + ")")
            .call(xAxis);
    //Define Y axis
    var yAxis = d3.svg.axis()
            .scale(yScale)
            .orient("left").ticks(5)

//Create Y axis
    chart.append("g")
                    .attr("class", "axis")
                    .attr("transform", "translate(30,0)")
                    .call(yAxis);

这里的translate方法接收两个参数,分别是水平位移与垂直位移。当然我们也可以配合class,来给坐标轴应用样式。

.axis path,
.axis line {
    fill: none;
    stroke: black;
    shape-rendering: crispEdges;
}

.axis text {
    font-family: sans-serif;
    font-size: 11px;
}

加上坐标轴我们的图形就漂亮多了,效果如下

快照4

demo见http://www.d3js.cn/demo/bar8.html

那这个呢# E:\AI_System\agent\knowledge_system\knowledge_visualizer.py import matplotlib.pyplot as plt import networkx as nx from datetime import datetime import numpy as np from knowledge_manager import KnowledgeManager from self_directed_learning import AutonomousLearningEngine class KnowledgeVisualizer: def __init__(self, knowledge_manager, learning_engine=None): self.km = knowledge_manager self.learning_engine = learning_engine def visualize_knowledge_graph(self, min_strength=0.1, figsize=(14, 10)): """可视化知识图谱""" G = nx.DiGraph() # 添加知识节点 for kid, entry in self.km.knowledge_base["knowledge"].items(): G.add_node(kid, title=entry["title"], type="knowledge", category=entry.get("category", "未分类")) # 添加关系边 for rel in self.km.knowledge_base["relationships"]: if rel["strength"] >= min_strength: G.add_edge( rel["source"], rel["target"], rel_type=rel["type"], strength=rel["strength"] ) if len(G.nodes) == 0: print("知识库为空,无法生成图谱") return plt.figure(figsize=figsize) # 按类别着色 categories = set(nx.get_node_attributes(G, &#39;category&#39;).values()) color_map = plt.cm.tab10(np.linspace(0, 1, len(categories))) category_colors = {cat: color_map[i] for i, cat in enumerate(categories)} node_colors = [] for node in G.nodes: category = G.nodes[node].get(&#39;category&#39;, &#39;未分类&#39;) node_colors.append(category_colors[category]) # 使用弹簧布局 pos = nx.spring_layout(G, seed=42, k=0.15) # 绘制节点 nx.draw_networkx_nodes( G, pos, node_size=800, node_color=node_colors, alpha=0.9 ) # 绘制边 edge_colors = [] edge_widths = [] for u, v, d in G.edges(data=True): edge_colors.append(&#39;gray&#39;) edge_widths.append(d[&#39;strength&#39;] * 4 + 1) nx.draw_networkx_edges( G, pos, width=edge_widths, edge_color=edge_colors, alpha=0.6, arrows=True, arrowsize=15 ) # 绘制标签 labels = {node: data[&#39;title&#39;] for node, data in G.nodes(data=True)} nx.draw_networkx_labels( G, pos, labels=labels, font_size=9, font_family=&#39;sans-serif&#39; ) # 添加图例 legend_handles = [] for cat, color in category_colors.items(): legend_handles.append(plt.Line2D([0], [0], marker=&#39;o&#39;, color=&#39;w&#39;, markerfacecolor=color, markersize=10, label=cat)) plt.legend(handles=legend_handles, loc=&#39;best&#39;) plt.title("知识图谱", fontsize=16) plt.axis(&#39;off&#39;) plt.tight_layout() plt.show() def visualize_knowledge_timeline(self): """可视化知识创建时间线""" if not self.km.knowledge_base["knowledge"]: print("知识库为空") return dates = [] for entry in self.km.knowledge_base["knowledge"].values(): dates.append(datetime.fromisoformat(entry["created_at"])) # 按月统计 months = defaultdict(int) for date in dates: month_key = date.strftime("%Y-%m") months[month_key] += 1 # 按时间排序 sorted_months = sorted(months.items(), key=lambda x: x[0]) x = [item[0] for item in sorted_months] y = [item[1] for item in sorted_months] plt.figure(figsize=(12, 6)) plt.plot(x, y, marker=&#39;o&#39;, linestyle=&#39;-&#39;, color=&#39;b&#39;) plt.fill_between(x, y, color=&#39;skyblue&#39;, alpha=0.4) plt.title("知识创建时间线") plt.xlabel("月份") plt.ylabel("知识数量") plt.xticks(rotation=45) plt.grid(True, linestyle=&#39;--&#39;, alpha=0.7) plt.tight_layout() plt.show() def visualize_learning_progress(self): """可视化学习进度(如果学习引擎可用)""" if not self.learning_engine: print("未提供学习引擎") return # 获取核心能力数据 core_skills = self.learning_engine.learning_journey["core_skills"] if not core_skills: print("无核心能力数据") return skills = list(core_skills.keys()) values = list(core_skills.values()) # 创建雷达图 angles = np.linspace(0, 2 * np.pi, len(skills), endpoint=False).tolist() values += values[:1] # 闭合图形 angles += angles[:1] # 闭合角度 fig, ax = plt.subplots(figsize=(8, 8), subplot_kw=dict(polar=True)) ax.fill(angles, values, color=&#39;skyblue&#39;, alpha=0.25) ax.plot(angles, values, color=&#39;b&#39;, linewidth=2) # 设置标签 ax.set_xticks(angles[:-1]) ax.set_xticklabels(skills) ax.set_yticklabels([]) # 设置标题 plt.title("核心能力发展雷达图", size=16, y=1.1) plt.tight_layout() plt.show() # 学习时间分布 learning_times = [] for node in self.learning_engine.learning_journey["nodes"].values(): if node["title"] != "初始状态": learning_times.append(node["duration"]) if learning_times: plt.figure(figsize=(10, 6)) plt.hist(learning_times, bins=10, color=&#39;lightgreen&#39;, edgecolor=&#39;darkgreen&#39;) plt.title("学习时长分布") plt.xlabel("学习时长(小时)") plt.ylabel("频次") plt.grid(axis=&#39;y&#39;, alpha=0.75) plt.tight_layout() plt.show() # 使用示例 if __name__ == "__main__": km = KnowledgeManager() learner = AutonomousLearningEngine("user123", km) visualizer = KnowledgeVisualizer(km, learner) # 可视化知识图谱 visualizer.visualize_knowledge_graph() # 可视化时间线 visualizer.visualize_knowledge_timeline() # 可视化学习进度 visualizer.visualize_learning_progress()
最新发布
08-11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值