从 SQLite 数据库中检索和绘制有序的二维热图数据
Retrieving and plotting ordered, 2D heatmap data from a SQLite database
本周大部分时间我都在努力解决这个问题,我想我可能最适合在这里寻求帮助。我将二维数组数据存储在 SQLite 数据库中,我想获取和可视化这些数据。尽管我不确定如何处理,但我需要如何获取和绘制数据有很多限制。
所以,我有一个 table 包含以下内容的数据库:
| ID | SourceID | TargetID | Parameter | Values |
| 1 | 21 | 34 | 23.46513 | 0.12654 |
| 2 | 21 | 34 | 23.46513 | 0.25478 |
| 3 | 21 | 46 | 23.46513 | 0.43564 |
| 4 | 21 | 46 | 23.46513 | 1.02487 |
| 5 | 34 | 21 | 14.56319 | 0.01476 |
| 6 | 34 | 21 | 14.56319 | 0.87265 |
| 7 | 34 | 46 | 14.56319 | 0.46478 |
| 8 | 34 | 46 | 14.56319 | 0.13665 |
| 9 | 46 | 21 | 7.99581 | 0.04189 |
| 10 | 46 | 21 | 7.99581 | 0.91754 |
| 11 | 46 | 34 | 7.99581 | 0.73688 |
| 12 | 46 | 34 | 7.99581 | 0.24299 |
该数据集的一些特征需要注意:
ID
是关键并且是唯一的
SourceID
和 TargetID
值来自同一组。在本例中,它们都包含 {21, 34, 46}。 SourceID
列构成热图的 x 轴数据,TargetID
列构成 y 轴数据。
Values
列包含必须在热图中绘制的数据。
Parameter
列是我需要用来对数据进行排序的列,因为我需要创建一个有序的热图。在这种情况下,Parameter
基于与每个 SourceID
和 TargetID
. 关联的值
以下 table 显示每个 SourceId
/TargetId
与 Parameter
值的关联:
| SourceID/TargetID | Parameter |
| 46 | 7.99581 |
| 34 | 14.56319 |
| 21 | 23.46513 |
根据我提出的另一个 ,我知道我可以根据最小值将此 table 减少为 (SourceId
, TargetId
) 的唯一组合Values
使用 SQL 查询,例如:
SELECT SourceID, TargetID, min(Values)
FROM dataset
GROUP BY SourceID, TargetID;
这会产生以下减少的 table:
| ID | SourceID | TargetID | SourceSort | Values |
| 1 | 21 | 34 | 23.46513 | 0.12654 |
| 3 | 21 | 46 | 23.46513 | 0.43564 |
| 5 | 34 | 21 | 14.56319 | 0.01476 |
| 8 | 34 | 46 | 14.56319 | 0.13665 |
| 9 | 46 | 21 | 7.99581 | 0.04189 |
| 12 | 46 | 34 | 7.99581 | 0.24299 |
我遇到的问题是我现在需要根据 Parameter
中的值来订购 table。如果我将 ORDER BY Parameter
添加到 SQL 查询,它会成功地对 SourceID
列进行排序,但是 TargetID
列不会根据此对具有相同 SourceID
。简而言之,我想获得以下 table:
| ID | SourceID | TargetID | Values |
| 12 | 46 | 34 | 0.24299 |
| 9 | 46 | 21 | 0.04189 |
| 8 | 34 | 46 | 0.13665 |
| 5 | 34 | 21 | 0.01476 |
| 3 | 21 | 46 | 0.43564 |
| 1 | 21 | 34 | 0.12654 |
此排序的基础示例:首先使用 Parameter
值根据 SourceID
顺序对 table 进行排序。随后,TargetID
基于 Parameter
顺序排序,对于 SourceID
值相等的行,例如,第 1 行 (ID=8
) 在第 2 行 (ID=5
) 因为 TargetID = 46
应该根据关联的 Parameter
值排在 TargetID = 21
之前。
最后,有了这个table,我需要构建一个热图:
(TargetID ordered by `Parameter ASC`)
^
|
|
----------------------------------
21 | 0.04189 | 0.01476 | 0 |
----------------------------------
34 | 0.24299 | 0 | 0.12654 |
----------------------------------
46 | 0 | 0.13665 | 0.43564 |
----------------------------------
| 46 | 34 | 21 --> (SourceID ordered by `Parameter ASC`)
为此,我使用 Python
Pandas
库,并使用 read_sql()
函数执行 SQL 查询。我发现我可以使用 matplotlib
的 pcolor()
函数来绘制热图。我想使用颜色图绘制二维数组中的值,并且我希望数据集的排序与上面完全相同。最后,我想将 SourceID
和 TargetID
值绘制为刻度标签。
这看起来应该是可行的,但到目前为止,我只能在没有根据 Parameter
排序的情况下生成热图。我不知道我是否最适合直接在 SQL 语句中解决排序位,或者我是否应该只获取数据然后对 [=49 返回的 DataFrame
进行排序=].
无论如何,我将不胜感激!如果有任何不清楚的地方,请告诉我,我会尽力澄清。
谢谢!
您的 sqlite table 格式不正确,因为参数值仅反映
参数与 SourceID 的关联,而不是 TargetID。
最好有两个table:
id_param:
id parameter
21 23.46513
34 14.56319
46 7.99581
dataset -- 注意这里没有参数栏:
ID SourceID TargetID Values
1 21 34 0.12654
2 21 34 0.25478
3 21 46 0.43564
4 21 46 1.02487
5 34 21 0.01476
6 34 21 0.87265
7 34 46 0.46478
8 34 46 0.13665
9 46 21 0.04189
10 46 21 0.91754
11 46 34 0.73688
12 46 34 0.24299
然后您可以使用 JOIN 在两者之间形成所需的关联
SourceID/Parameter 和 TargetID/Parameter:
SELECT d.SourceID, d.TargetID, min(d.`Values`) as min_value
FROM dataset d
JOIN id_param as ip1
ON d.SourceID = ip1.id
JOIN id_param as ip2
ON d.TargetID = ip2.id
GROUP BY SourceID, TargetID
ORDER BY ip1.parameter ASC, ip2.parameter ASC
例如,
import io
import sqlite3
import pandas as pd
import matplotlib.pyplot as plt
text = '''\
| ID | SourceID | TargetID | Parameter | Values |
| 1 | 21 | 34 | 23.46513 | 0.12654 |
| 2 | 21 | 34 | 23.46513 | 0.25478 |
| 3 | 21 | 46 | 23.46513 | 0.43564 |
| 4 | 21 | 46 | 23.46513 | 1.02487 |
| 5 | 34 | 21 | 14.56319 | 0.01476 |
| 6 | 34 | 21 | 14.56319 | 0.87265 |
| 7 | 34 | 46 | 14.56319 | 0.46478 |
| 8 | 34 | 46 | 14.56319 | 0.13665 |
| 9 | 46 | 21 | 7.99581 | 0.04189 |
| 10 | 46 | 21 | 7.99581 | 0.91754 |
| 11 | 46 | 34 | 7.99581 | 0.73688 |
| 12 | 46 | 34 | 7.99581 | 0.24299 |'''
def make_table(filename):
# make sqlite table
with sqlite3.connect(filename) as con:
df = pd.read_table(io.BytesIO(text), sep=r'\s*[|]\s*').iloc[:, 1:-1]
df.to_sql('dataset', con=con, if_exists='replace')
filename = '/tmp/data.sqlite'
make_table(filename)
with sqlite3.connect(filename) as con:
con.execute('DROP TABLE id_param')
sql = '''CREATE TABLE id_param
(id INTEGER PRIMARY KEY, parameter INTEGER)'''
con.execute(sql)
sql = '''INSERT INTO id_param
SELECT SourceID, Parameter
FROM dataset
GROUP BY SourceID'''
con.execute(sql)
sql = '''
SELECT d.SourceID, d.TargetID, min(d.`Values`) as min_value
FROM dataset d
JOIN id_param as ip1
ON d.SourceID = ip1.id
JOIN id_param as ip2
ON d.TargetID = ip2.id
GROUP BY SourceID, TargetID
ORDER BY ip1.parameter ASC, ip2.parameter ASC
'''
df = pd.read_sql(sql, con)
print(df)
产量
SourceID TargetID min_value
0 46 34 0.24299
1 46 21 0.04189
2 34 46 0.13665
3 34 21 0.01476
4 21 46 0.43564
5 21 34 0.12654
将 sqlite table 转换为 Matplotlib pcolor
绘制热图所需的格式的最简单方法(我知道)是使用 Pandas DataFrame 的 pivot
方法。由于此 pivot
将对列和行重新排序,因此无需为 SQL 查询生成的顺序大惊小怪。相反,更容易修复 Pandas:
中的顺序
import io
import sqlite3
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
text = '''\
| ID | SourceID | TargetID | Parameter | Values |
| 1 | 21 | 34 | 23.46513 | 0.12654 |
| 2 | 21 | 34 | 23.46513 | 0.25478 |
| 3 | 21 | 46 | 23.46513 | 0.43564 |
| 4 | 21 | 46 | 23.46513 | 1.02487 |
| 5 | 34 | 21 | 14.56319 | 0.01476 |
| 6 | 34 | 21 | 14.56319 | 0.87265 |
| 7 | 34 | 46 | 14.56319 | 0.46478 |
| 8 | 34 | 46 | 14.56319 | 0.13665 |
| 9 | 46 | 21 | 7.99581 | 0.04189 |
| 10 | 46 | 21 | 7.99581 | 0.91754 |
| 11 | 46 | 34 | 7.99581 | 0.73688 |
| 12 | 46 | 34 | 7.99581 | 0.24299 |'''
def make_table(filename):
# make sqlite table
with sqlite3.connect(filename) as con:
df = pd.read_table(io.BytesIO(text), sep=r'\s*[|]\s*').iloc[:, 1:-1]
df.to_sql('dataset', con=con, if_exists='replace')
filename = '/tmp/data.sqlite'
make_table(filename)
with sqlite3.connect(filename) as con:
sql = '''
SELECT SourceID, TargetID, min(`Values`) as min_value
FROM dataset
GROUP BY SourceID, TargetID
'''
df = pd.read_sql(sql, con)
table = df.pivot(index='SourceID', columns='TargetID', values='min_value')
sql = 'SELECT DISTINCT SourceID FROM dataset ORDER BY Parameter ASC'
order = pd.read_sql(sql, con)['SourceID']
table = table.reindex(index=order, columns=order)
fig, ax = plt.subplots()
ax.pcolor(table.values, cmap=plt.get_cmap('jet'),
vmin=df['min_value'].min(), vmax=df['min_value'].max())
ax.set_xticks(np.arange(table.shape[1] + 1)+0.5, minor=False)
ax.set_xticklabels(table.columns, minor=False)
ax.set_yticks(np.arange(table.shape[0] + 1)+0.5, minor=False)
ax.set_yticklabels(table.index, minor=False)
ax.set_xlim(0, table.shape[1])
ax.set_ylim(0, table.shape[0])
plt.show()
产量
本周大部分时间我都在努力解决这个问题,我想我可能最适合在这里寻求帮助。我将二维数组数据存储在 SQLite 数据库中,我想获取和可视化这些数据。尽管我不确定如何处理,但我需要如何获取和绘制数据有很多限制。
所以,我有一个 table 包含以下内容的数据库:
| ID | SourceID | TargetID | Parameter | Values |
| 1 | 21 | 34 | 23.46513 | 0.12654 |
| 2 | 21 | 34 | 23.46513 | 0.25478 |
| 3 | 21 | 46 | 23.46513 | 0.43564 |
| 4 | 21 | 46 | 23.46513 | 1.02487 |
| 5 | 34 | 21 | 14.56319 | 0.01476 |
| 6 | 34 | 21 | 14.56319 | 0.87265 |
| 7 | 34 | 46 | 14.56319 | 0.46478 |
| 8 | 34 | 46 | 14.56319 | 0.13665 |
| 9 | 46 | 21 | 7.99581 | 0.04189 |
| 10 | 46 | 21 | 7.99581 | 0.91754 |
| 11 | 46 | 34 | 7.99581 | 0.73688 |
| 12 | 46 | 34 | 7.99581 | 0.24299 |
该数据集的一些特征需要注意:
ID
是关键并且是唯一的SourceID
和TargetID
值来自同一组。在本例中,它们都包含 {21, 34, 46}。SourceID
列构成热图的 x 轴数据,TargetID
列构成 y 轴数据。Values
列包含必须在热图中绘制的数据。Parameter
列是我需要用来对数据进行排序的列,因为我需要创建一个有序的热图。在这种情况下,Parameter
基于与每个SourceID
和TargetID
. 关联的值
以下 table 显示每个 SourceId
/TargetId
与 Parameter
值的关联:
| SourceID/TargetID | Parameter |
| 46 | 7.99581 |
| 34 | 14.56319 |
| 21 | 23.46513 |
根据我提出的另一个 SourceId
, TargetId
) 的唯一组合Values
使用 SQL 查询,例如:
SELECT SourceID, TargetID, min(Values)
FROM dataset
GROUP BY SourceID, TargetID;
这会产生以下减少的 table:
| ID | SourceID | TargetID | SourceSort | Values |
| 1 | 21 | 34 | 23.46513 | 0.12654 |
| 3 | 21 | 46 | 23.46513 | 0.43564 |
| 5 | 34 | 21 | 14.56319 | 0.01476 |
| 8 | 34 | 46 | 14.56319 | 0.13665 |
| 9 | 46 | 21 | 7.99581 | 0.04189 |
| 12 | 46 | 34 | 7.99581 | 0.24299 |
我遇到的问题是我现在需要根据 Parameter
中的值来订购 table。如果我将 ORDER BY Parameter
添加到 SQL 查询,它会成功地对 SourceID
列进行排序,但是 TargetID
列不会根据此对具有相同 SourceID
。简而言之,我想获得以下 table:
| ID | SourceID | TargetID | Values |
| 12 | 46 | 34 | 0.24299 |
| 9 | 46 | 21 | 0.04189 |
| 8 | 34 | 46 | 0.13665 |
| 5 | 34 | 21 | 0.01476 |
| 3 | 21 | 46 | 0.43564 |
| 1 | 21 | 34 | 0.12654 |
此排序的基础示例:首先使用 Parameter
值根据 SourceID
顺序对 table 进行排序。随后,TargetID
基于 Parameter
顺序排序,对于 SourceID
值相等的行,例如,第 1 行 (ID=8
) 在第 2 行 (ID=5
) 因为 TargetID = 46
应该根据关联的 Parameter
值排在 TargetID = 21
之前。
最后,有了这个table,我需要构建一个热图:
(TargetID ordered by `Parameter ASC`)
^
|
|
----------------------------------
21 | 0.04189 | 0.01476 | 0 |
----------------------------------
34 | 0.24299 | 0 | 0.12654 |
----------------------------------
46 | 0 | 0.13665 | 0.43564 |
----------------------------------
| 46 | 34 | 21 --> (SourceID ordered by `Parameter ASC`)
为此,我使用 Python
Pandas
库,并使用 read_sql()
函数执行 SQL 查询。我发现我可以使用 matplotlib
的 pcolor()
函数来绘制热图。我想使用颜色图绘制二维数组中的值,并且我希望数据集的排序与上面完全相同。最后,我想将 SourceID
和 TargetID
值绘制为刻度标签。
这看起来应该是可行的,但到目前为止,我只能在没有根据 Parameter
排序的情况下生成热图。我不知道我是否最适合直接在 SQL 语句中解决排序位,或者我是否应该只获取数据然后对 [=49 返回的 DataFrame
进行排序=].
无论如何,我将不胜感激!如果有任何不清楚的地方,请告诉我,我会尽力澄清。
谢谢!
您的 sqlite table 格式不正确,因为参数值仅反映 参数与 SourceID 的关联,而不是 TargetID。
最好有两个table:
id_param:
id parameter
21 23.46513
34 14.56319
46 7.99581
dataset -- 注意这里没有参数栏:
ID SourceID TargetID Values
1 21 34 0.12654
2 21 34 0.25478
3 21 46 0.43564
4 21 46 1.02487
5 34 21 0.01476
6 34 21 0.87265
7 34 46 0.46478
8 34 46 0.13665
9 46 21 0.04189
10 46 21 0.91754
11 46 34 0.73688
12 46 34 0.24299
然后您可以使用 JOIN 在两者之间形成所需的关联 SourceID/Parameter 和 TargetID/Parameter:
SELECT d.SourceID, d.TargetID, min(d.`Values`) as min_value
FROM dataset d
JOIN id_param as ip1
ON d.SourceID = ip1.id
JOIN id_param as ip2
ON d.TargetID = ip2.id
GROUP BY SourceID, TargetID
ORDER BY ip1.parameter ASC, ip2.parameter ASC
例如,
import io
import sqlite3
import pandas as pd
import matplotlib.pyplot as plt
text = '''\
| ID | SourceID | TargetID | Parameter | Values |
| 1 | 21 | 34 | 23.46513 | 0.12654 |
| 2 | 21 | 34 | 23.46513 | 0.25478 |
| 3 | 21 | 46 | 23.46513 | 0.43564 |
| 4 | 21 | 46 | 23.46513 | 1.02487 |
| 5 | 34 | 21 | 14.56319 | 0.01476 |
| 6 | 34 | 21 | 14.56319 | 0.87265 |
| 7 | 34 | 46 | 14.56319 | 0.46478 |
| 8 | 34 | 46 | 14.56319 | 0.13665 |
| 9 | 46 | 21 | 7.99581 | 0.04189 |
| 10 | 46 | 21 | 7.99581 | 0.91754 |
| 11 | 46 | 34 | 7.99581 | 0.73688 |
| 12 | 46 | 34 | 7.99581 | 0.24299 |'''
def make_table(filename):
# make sqlite table
with sqlite3.connect(filename) as con:
df = pd.read_table(io.BytesIO(text), sep=r'\s*[|]\s*').iloc[:, 1:-1]
df.to_sql('dataset', con=con, if_exists='replace')
filename = '/tmp/data.sqlite'
make_table(filename)
with sqlite3.connect(filename) as con:
con.execute('DROP TABLE id_param')
sql = '''CREATE TABLE id_param
(id INTEGER PRIMARY KEY, parameter INTEGER)'''
con.execute(sql)
sql = '''INSERT INTO id_param
SELECT SourceID, Parameter
FROM dataset
GROUP BY SourceID'''
con.execute(sql)
sql = '''
SELECT d.SourceID, d.TargetID, min(d.`Values`) as min_value
FROM dataset d
JOIN id_param as ip1
ON d.SourceID = ip1.id
JOIN id_param as ip2
ON d.TargetID = ip2.id
GROUP BY SourceID, TargetID
ORDER BY ip1.parameter ASC, ip2.parameter ASC
'''
df = pd.read_sql(sql, con)
print(df)
产量
SourceID TargetID min_value
0 46 34 0.24299
1 46 21 0.04189
2 34 46 0.13665
3 34 21 0.01476
4 21 46 0.43564
5 21 34 0.12654
将 sqlite table 转换为 Matplotlib pcolor
绘制热图所需的格式的最简单方法(我知道)是使用 Pandas DataFrame 的 pivot
方法。由于此 pivot
将对列和行重新排序,因此无需为 SQL 查询生成的顺序大惊小怪。相反,更容易修复 Pandas:
import io
import sqlite3
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
text = '''\
| ID | SourceID | TargetID | Parameter | Values |
| 1 | 21 | 34 | 23.46513 | 0.12654 |
| 2 | 21 | 34 | 23.46513 | 0.25478 |
| 3 | 21 | 46 | 23.46513 | 0.43564 |
| 4 | 21 | 46 | 23.46513 | 1.02487 |
| 5 | 34 | 21 | 14.56319 | 0.01476 |
| 6 | 34 | 21 | 14.56319 | 0.87265 |
| 7 | 34 | 46 | 14.56319 | 0.46478 |
| 8 | 34 | 46 | 14.56319 | 0.13665 |
| 9 | 46 | 21 | 7.99581 | 0.04189 |
| 10 | 46 | 21 | 7.99581 | 0.91754 |
| 11 | 46 | 34 | 7.99581 | 0.73688 |
| 12 | 46 | 34 | 7.99581 | 0.24299 |'''
def make_table(filename):
# make sqlite table
with sqlite3.connect(filename) as con:
df = pd.read_table(io.BytesIO(text), sep=r'\s*[|]\s*').iloc[:, 1:-1]
df.to_sql('dataset', con=con, if_exists='replace')
filename = '/tmp/data.sqlite'
make_table(filename)
with sqlite3.connect(filename) as con:
sql = '''
SELECT SourceID, TargetID, min(`Values`) as min_value
FROM dataset
GROUP BY SourceID, TargetID
'''
df = pd.read_sql(sql, con)
table = df.pivot(index='SourceID', columns='TargetID', values='min_value')
sql = 'SELECT DISTINCT SourceID FROM dataset ORDER BY Parameter ASC'
order = pd.read_sql(sql, con)['SourceID']
table = table.reindex(index=order, columns=order)
fig, ax = plt.subplots()
ax.pcolor(table.values, cmap=plt.get_cmap('jet'),
vmin=df['min_value'].min(), vmax=df['min_value'].max())
ax.set_xticks(np.arange(table.shape[1] + 1)+0.5, minor=False)
ax.set_xticklabels(table.columns, minor=False)
ax.set_yticks(np.arange(table.shape[0] + 1)+0.5, minor=False)
ax.set_yticklabels(table.index, minor=False)
ax.set_xlim(0, table.shape[1])
ax.set_ylim(0, table.shape[0])
plt.show()
产量