Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
f6bbe31
BaseType
SAKURA-CAT Dec 29, 2023
bddcd26
fix #79
SAKURA-CAT Dec 29, 2023
7101e79
key check
SAKURA-CAT Dec 29, 2023
18bd7e7
base type
SAKURA-CAT Dec 29, 2023
d0e9a0a
feat: custom data
SAKURA-CAT Dec 29, 2023
c3e3683
group
SAKURA-CAT Dec 29, 2023
99efc7e
rebase
SAKURA-CAT Dec 29, 2023
61ff760
unkonw chart type
SAKURA-CAT Dec 29, 2023
d1d0e0d
fix #102
SAKURA-CAT Dec 29, 2023
972ac4d
Optimize performance
SAKURA-CAT Dec 29, 2023
e923e03
Update LineChart.vue
SAKURA-CAT Dec 29, 2023
9a75684
update interactions
SAKURA-CAT Dec 29, 2023
15d678c
fix: summary
Feudalman Dec 29, 2023
1a89ad8
Merge branch 'fixbug/type-check' of github.com:SwanHubX/swanlab into …
Feudalman Dec 29, 2023
abf3d37
fix error type crash
SAKURA-CAT Dec 29, 2023
c457c1a
hide zoom
SAKURA-CAT Dec 29, 2023
2aff4a4
add title
SAKURA-CAT Dec 29, 2023
2ca28cd
Update LineChart.vue
SAKURA-CAT Dec 29, 2023
289c81e
toFixed
SAKURA-CAT Dec 29, 2023
5aca9cc
delete formatter
SAKURA-CAT Dec 29, 2023
6690654
add code-snippets
SAKURA-CAT Dec 30, 2023
689bb1a
fix: unquote
Feudalman Dec 30, 2023
c0e34d6
ui: some text
Feudalman Dec 28, 2023
98fb69a
refactor: init table layout
Feudalman Dec 28, 2023
90c6b9e
refactor: table ui
Feudalman Dec 29, 2023
1b65139
feat: real time resizing
Feudalman Dec 29, 2023
01682de
fix:width
Feudalman Dec 29, 2023
d909d05
feat: new table
Feudalman Dec 30, 2023
2817cac
fix: hover style while dragging
Feudalman Dec 30, 2023
e195397
fix: rename
Feudalman Dec 30, 2023
392d72c
fix:overflow
Feudalman Dec 30, 2023
05b5663
fix: init width and resize
Feudalman Dec 30, 2023
19b24c4
fix: ui
Feudalman Dec 30, 2023
8c97947
ui: some border
Feudalman Dec 30, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions .vscode/swanlab.code-snippets
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,90 @@
""
],
},
"vue-chart": {
"prefix": "vue-chart",
"body": [
"<template>",
" <!-- 图表标题 -->",
" <p class=\"text-center font-semibold\">{{ title }}</p>",
" <!-- 如果图表数据错误 -->",
" <div class=\"flex flex-col justify-center grow text-dimmer gap-2\" v-if=\"error\">",
" <SLIcon class=\"mx-auto h-5 w-5\" icon=\"error\" />",
" <p class=\"text-center text-xs\">",
" <!-- 在此处显示错误信息 -->",
" </p>",
" </div>",
" <!-- 如果图表数据正确 -->",
" <template v-else>",
" <!-- 在此处完成图表主体定义 -->",
" <!-- 放大效果弹窗 -->",
" <SLModal class=\"p-10 pt-0 overflow-hidden\" max-w=\"-1\" v-model=\"isZoom\"> </SLModal>",
" </template>",
"</template>",
"",
"<script setup>",
"/**",
" * @description: $1",
" * @file: ${TM_FILENAME} ",
" * @since: ${CURRENT_YEAR}-${CURRENT_MONTH}-${CURRENT_DATE} ${CURRENT_HOUR}:${CURRENT_MINUTE}:${CURRENT_SECOND} ",
"**/",
"import SLModal from '@swanlab-vue/components/SLModal.vue'",
"import SLIcon from '@swanlab-vue/components/SLIcon.vue'",
"import { ref } from 'vue'",
"import { useExperimentStroe } from '@swanlab-vue/store'",
"import { addTaskToBrowserMainThread } from '@swanlab-vue/utils/browser'",
"import * as UTILS from './utils'",
"",
"// ---------------------------------- 配置 ----------------------------------",
"const experimentStore = useExperimentStroe()",
"const props = defineProps({",
" title: {",
" type: String,",
" required: true",
" },",
" chart: {",
" type: Object,",
" required: true",
" }",
"})",
"",
"// ---------------------------------- 错误处理,如果chart.error存在,则下面的api都将不应该被执行 ----------------------------------",
"",
"const error = ref(props.chart.error)",
"",
"// ---------------------------------- 组件渲染逻辑 ----------------------------------",
"",
"// ---------------------------------- 数据格式化 ----------------------------------",
"",
"// ---------------------------------- 渲染、重渲染功能 ----------------------------------",
"",
"// 渲染",
"const render = (data) => {}",
"// 重渲染",
"const change = (data) => {}",
"",
"// ---------------------------------- 放大功能 ----------------------------------",
"// 是否放大",
"const isZoom = ref(false)",
"// 放大数据",
"const zoom = (data) => {",
" isZoom.value = true",
" // 放大后图表的高度",
" const height = window.innerHeight * 0.6",
" addTaskToBrowserMainThread(() => {})",
"}",
"",
"// ---------------------------------- 暴露api ----------------------------------",
"defineExpose({",
" render,",
" change,",
" zoom",
"})",
"</script>",
"",
"<style lang=\"scss\" scoped></style>",
""
],
"description": "vue-chart"
}
}
1 change: 1 addition & 0 deletions swanlab/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from .database import (
init,
log,
BaseType,
)
from .utils import get_package_version

Expand Down
13 changes: 10 additions & 3 deletions swanlab/database/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
from datetime import datetime
from ..env import swc
from ..log import swanlog as swl
from ..utils.file import check_key_format

from .modules import BaseType


sd = None

Expand Down Expand Up @@ -105,8 +109,11 @@ def log(data: dict, step: int = None):
raise TypeError("'step' must be an integer not less than zero.")
for key in data:
# 遍历字典的key,记录到本地文件中
# TODO 检查数据类型
sd.add(key, data[key], step=step)
d = data[key]
# 检查key的类型
check_key_format(key)
# 数据类型的检查将在创建chart配置的时候完成,因为数据类型错误并不会影响实验进行
sd.add(key, d, step=step)


__all__ = ["log", "init"]
__all__ = ["log", "init", "BaseType"]
125 changes: 96 additions & 29 deletions swanlab/database/chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from ..utils import create_time, get_a_lock
from typing import List, Union
from ..log import swanlog as swl
from .modules import BaseType


class ChartTable(ProjectTablePoxy):
Expand All @@ -27,22 +28,31 @@ def __init__(self, experiment_id: int):
super().__init__(data, self.path)
# 保存表单信息
self.save_no_lock()
# 当前正在使用的图表
self.now_charts = []

def new_chart(self, chart_id: int, namespace: str, reference: str, chart_type: str) -> dict:
def new_chart(
self,
chart_id: int,
namespace: str = "default",
reference: str = "step",
chart_type: str = "default",
config: dict = {},
) -> dict:
"""创建一个新chart的配置选项"""
return {
"chart_id": chart_id,
"namespace": namespace,
"source": [],
"reference": reference,
"type": chart_type,
"config": {},
"config": config,
"experiment_id": self.experiment_id,
"update_time": create_time(),
"create_time": create_time(),
}

def add_chart(self, data, chart):
def add_chart(self, charts, chart):
"""添加图表到配置,同时更新组

Parameters
Expand All @@ -53,17 +63,19 @@ def add_chart(self, data, chart):
添加的图表
"""
namespace: str = chart["namespace"]
namespaces: list = data["namespaces"]
data["charts"].append(chart)
namespaces: list = charts["namespaces"]
charts["charts"].append(chart)
# 遍历data["namespaces"]
ns: dict = None
exists: bool = False
for ns in namespaces:
if ns["namespace"] == namespace:
exists = True
break
# 如果命名空间不存在,添加
if ns is None:
if not exists:
swl.debug(f"Namespace {namespace} not found, add.")
ns = {"namespace": "default", "charts": []}
ns = {"namespace": namespace, "charts": []}
if ns["namespace"] == "default":
swl.debug(f"Namespace {namespace} Add to the beginning")
namespaces.insert(0, ns)
Expand All @@ -74,36 +86,91 @@ def add_chart(self, data, chart):
ns["charts"].append(chart["chart_id"])
swl.debug(f"Chart {chart['chart_id']} add, now charts: " + str(ns["charts"]))

def add(
self,
tag: Union[str, List[str]],
namespace: str = "default",
reference: str = "step",
chart_type: str = "default",
):
def add(self, tag: str, data: Union[float, int, BaseType]):
"""添加一张图表

Parameters
----------
tag : Union[str, List[str]]
图表标签,可以是一个标签,也可以是多个标签,但必须是字符串或者字符串列表
单标签代表创建的图表只包含一个数据源,多标签代表创建的图表包含多个数据源
namespace : str, optional
命名空间,用于区分不同的图表在前端的显示位置
reference : str, optional
参考系,用于区分不同的图表表格的组织方式
chart_type : str, optional
图表类型,用于区分不同的图表的显示方式,如折线图,柱状图等
tag : str
图表标签
data: Union[float, int, BaseType]
数据源,可以是一个数字,也可以是一个swanlab.BaseType的子类
"""
with get_a_lock(self.path) as f:
data = ujson.load(f)
# 记录数据
data["_sum"] += 1
chart = self.new_chart(data["_sum"], namespace, reference, chart_type)
charts = ujson.load(f)
# 记录图表数量,+1
charts["_sum"] += 1
chart = self.new_chart(charts["_sum"])
# 如果data是BaseType类型,解构,并且修改一些必要参数
if issubclass(type(data), BaseType):
chart["namespace"], (chart["type"], data_types), chart["reference"], chart["config"] = data.__next__()
else:
data_types = [float, int]
# 如果data不是data_types中的类型,尝试转换为这两个类型中的一个(优先转换为float)
if not isinstance(data, tuple(data_types)):
try:
data = self.try_convert(data, data_types)
except:
# 此时代表数据异常,拿到data的__class__.__name__,记录到chart.error中并保存
class_name = data.__class__.__name__
excepted = [i.__name__ for i in data_types]
swl.error(f"Data type error, tag: {tag}, data type: {class_name}, excepted: {excepted}")
chart["error"] = {"data_class": class_name, "excepted": excepted}
chart["source"].append(tag)
# 添加图表
self.add_chart(data, chart)
self.add_chart(charts, chart)
f.truncate(0)
f.seek(0)
ujson.dump(data, f, ensure_ascii=False)
ujson.dump(charts, f, ensure_ascii=False)
# 记录当前chart期望的数据类型,这个字段不会被保存到文件中
chart["excepted"] = data_types
self.now_charts.append(chart)
f.close()

def is_chart_error(self, tag):
"""遍历所有自动创建的chart,检查对应的tag的chart是否存在error字段

Parameters
----------
tag : str
tag名称
"""
for chart in self.now_charts:
if tag in chart["source"] and "error" in chart:
return chart["error"]
return False

def try_convert(self, value, data_types):
# 如果当前data已经是data_types中的类型,直接返回
if isinstance(value, tuple(data_types)):
return value
for data_type in data_types:
try:
converted_value = data_type(value)
return converted_value
except (ValueError, TypeError):
# 如果转换失败,继续尝试下一种类型
continue

# 如果所有类型都尝试过仍然失败,则抛出异常
raise ValueError(f"Unable to convert {value} to any of the specified types.")

def try_convert_data(self, data, tag):
"""尝试将data转换为data_types中的类型,如果转换失败,返回None
如果所有类型都尝试过仍然失败,则抛出异常
调用这个函数代表用户的图表已经创建并且传入了与之前不同的数据类型
"""
# 首先寻找tag对应的chart
for chart in self.now_charts:
if tag in chart["source"]:
data_types = chart["excepted"]
break
# 如果当前data已经是data_types中的类型,直接返回
if isinstance(data, tuple(data_types)):
return data
try:
return self.try_convert(data, data_types)
except:
raise ValueError(
f"Unable to convert {data} to any of the specified types. This Error means that you have changed the data type of the chart, please check the data type of the chart."
)
Loading