dak ブログ

python、rubyなどのプログラミング、MySQL、サーバーの設定などの備忘録。レゴの写真も。

python でインスタンス変数の一覧を参照

2021-12-31 14:10:01 | python
python でインスタンス変数の一覧を参照する方法のメモ。

__dict__ や vars() でインスタンス変数とその値を参照することができます。
未定義の変数を get() で参照しようとすると、None が返却されます。
import sys

class TestClass:
    def __init__(self):
        self.var1 = "value1"
        self.var2 = "value2"

    def output_vars(self):
        print("* __dict__")
        for var, val in self.__dict__.items():
            print("%s -- %s" % (var, val))

        print("* vars()")
        for var, val in vars(self).items():
            print('%s -- %s' % (var, val))

        print("* vars().get()")
        for var in ['var1', 'var2', 'var3']:
            val = vars(self).get(var)
            print('%s -- %s' % (var, val))

t = TestClass()
t.output_vars()

実行結果
* __dict__
var1 -- value1
var2 -- value2
* vars()
var1 -- value1
var2 -- value2
* vars().get()
var1 -- value1
var2 -- value2
var3 -- None

python で相対 URL を絶対 URL に変換

2021-12-28 23:32:36 | python
python で相対 URL を絶対 URL に変換する方法のメモ。

urllib.parse.urljoin() で相対 URL を絶対 URL に変換することができます。
import urllib
rel_url = '../test/test.html'
base_url = 'http://localhost/dir1/dir2/dir3/page.html'
urllib.parse.urljoin(base_url, rel_url)
> 'http://localhost/dir1/dir2/test/test.html'


xpath で除外条件を指定

2021-12-21 20:43:35 | python
xpath で除外条件を指定する方法のメモ。
特定のタグを除外する場合には、/*[not(self::{タグ})] のように xpath を記述します。
import sys
import lxml.html

htmlstr = """
<html>
<body>
<div class="a">
<div class="aa">div_aa</div>
<div class="ab">div_ab</div>
<div class="ac">div_ac</div>
<script></script>
<style></style>
</div>
</body>
</html>
"""

dom = lxml.html.fromstring(htmlstr)
nodes = dom.xpath('//div[@class="a"]/*[not(self::script or self::style)]')

for node in nodes:
    for text in node.itertext():
        print(text)

web ページからのテキスト抽出で、script タグなど特定のタグを常に除外するなら、
以下のように特定のタグを除外してから xpath で条件に合うタグを取得する方が楽かもしれません。
nodes = dom.xpath('//script|//style')
for node in nodes:
    node.getparent().remove(node)

nodes = dom.xpath('//div[@class="a"]/*')
for node in nodes:
    for text in node.itertext():
        print(text)


lxml で html からテキストを抽出する方法

2021-12-16 23:48:44 | python
lxml で html からテキストを抽出する方法のメモ。

text では、先頭の子要素のテキストしか抽出できませんが、
itertext() では、配下の全要素のテキストを抽出することができます。
import sys
import lxml.html

htmlstr = '<html><body><div class="a">abc<h1>h1</h1>def<h2>h2</h2>ghi</div></bo\
dy></html>'

dom = lxml.html.fromstring(htmlstr)
div = dom.xpath('//div[@class="a"]')[0]

print('div.text')
print(div.text)

print('div.itertext()')
print('\n'.join(div.itertext()))

実行結果
div.text
abc
div.itertext()
abc
h1
def
h2
ghi


python の lxml で html の dom を操作してみる

2021-12-14 00:03:52 | python
python の lxml で html の dom を操作してみる。
import sys
import lxml.html

# div/p0-p4                                                                     
htmlstr = '<html><body><div class="a"><p>p0</p><p>p1</p><p>p2</p><p>p3</p><p>p4</p></div></body></html>'

dom = lxml.html.fromstring(htmlstr)
nodes = dom.xpath('//div[@class="a"]')
div = nodes[0]

# p0 を削除                                                                     
div.remove(div[0])
print(lxml.html.tostring(dom).decode('utf-8'))

# p2 を検索                                                                     
idx = div.index(div[1])
print('idx: %d' % (idx))

# p2 を更新                                                                     
div[idx] = lxml.html.fromstring('<p>p2 new</p>')
print(lxml.html.tostring(dom).decode('utf-8'))

# body を出力                                                                   
print(lxml.html.tostring(div.getparent()).decode('utf-8'))

# p5 を追加                                                                     
p5 = lxml.html.fromstring('<p>p5</p>')
div.append(p5)
print(lxml.html.tostring(dom).decode('utf-8'))

実行結果
<html><body><div class="a"><p>p1</p><p>p2</p><p>p3</p><p>p4</p></div></body></html>
idx: 1
<html><body><div class="a"><p>p1</p><p>p2 new</p><p>p3</p><p>p4</p></div></body></html>
<body><div class="a"><p>p1</p><p>p2 new</p><p>p3</p><p>p4</p></div></body>
<html><body><div class="a"><p>p1</p><p>p2 new</p><p>p3</p><p>p4</p><p>p5</p></div></body></html>

sort コマンドでの複数キーによるソート

2021-12-08 20:49:47 | linux
sort コマンドで複数のキーによるソート方法のメモ。

sort コマンドでは、カラム毎に文字列/数値、昇順/降順を組み合わせてソートすることができます。
以下は sort -k 2n -k 3nr -k 1 の実行例ですが、次の条件でソートしています。
 -k 2n: 第2カラムを数値の昇順
 -k 3nr: 第3カラムを数値の降順
 -k 1: 第1カラムを文字列の昇順
$ cat test.txt
abc1	1	100
abc2	1	50
abc3	1	100
abc4	1	50
def1	2	50
def2	2	25
def3	2	50
def4	2	25
ghi1	5	20
ghi2	5	10
ghi3	5	20
ghi4	5	10
jkl1	10	10
jkl2	10	5
jkl3	10	10
jkl4	10	5

$ cat test2.txt | sort -k 2n -k 3nr -k 1
abc1	1	100
abc3	1	100
abc2	1	50
abc4	1	50
def1	2	50
def3	2	50
def2	2	25
def4	2	25
ghi1	5	20
ghi3	5	20
ghi2	5	10
ghi4	5	10
jkl1	10	10
jkl3	10	10
jkl2	10	5
jkl4	10	5


awk での cut

2021-12-07 23:49:17 | linux
cut コマンドで tsv ファイルの指定カラムの値のみを抽出することができます。
$ cat test1.txt
col11	col12	col13	col14
col21	col22	col23	col24
$ cat test1.txt | cut -f 1,2
col11	col12
col21	col22

cut コマンドで、カラムの順番を変更して 1カラム目、3カラム目、2カラム目 の順で項目を指定しても、
指定した順の結果は得られません。
$ cat test1.txt | cut -f 1,3,2
col11	col12	col13
col21	col22	col23

awk ならカラムの順番を任意の順で出力することができます。
$ cat test1.txt | awk -F "\t" '{OFS="\t"; print $1, $3, $3, $2}'
col11	col13	col13	col12
col21	col23	col23	col22



d3.js の散布図でマウスオーバーでメッセージを表示

2021-12-03 19:41:38 | javascript
d3.js で散布図でマウスオーバーでメッセージを表示する方法のメモ。
on("mouseover", function (e) { ... }) でマウスオーバー時のイベントを処理します。

メッセージは div タグで作成しておき、マウスオーバー時に内部の html を変更して表示するようにします。
以下のようなイメージです。
const tooltip = d3.select("#scatter")
    .append("div")
    .style("position", "absolute")
    .style("text-align", "left")
    .style("background", "#ffffff")
    .style("border", "1px solid #000000")
    .style("padding", "10px")
    .style("opacity", 0)
    ;

svg.append("g")
.selectAll("circle")
.data(dataset)
.enter()
....
.on("mouseover", function (e) {
    const d = e.target.__data__;
    tooltip
    .style("left", e.x + 30 + 'px')
    .style("top", e.y + 'px')
    .html(
        "id: " + d[3] + ""
        + "[" + d[0] + ", " + d[1] + "]" + ""
        + "value: " + d[2]
    )
    .style("opacity", 1)
    ;
})
.on("mouseout", function (d) {
    tooltip
    .style("opacity", 0)
    ;
})
;

HTML 全体は以下の通りです。
<html>
<head>

<title>d3.js test</title>
</head>
<body>
d3.js test
<script src="../d3.min.js"></script> <script type="text/javascript"> const dataset = [ [0.0, 0.0, 0.0, "p00"], [1.0, 2.0, 0.1, "p01"], [1.5, 4.0, 0.2, "p02"], [2.0, 1.5, 0.3, "p03"], [1.5, 4.0, 0.4, "p04"], [2.5, 3.5, 0.5, "p05"], [1.0, 4.0, 0.6, "p06"], [1.5, 3.5, 0.7, "p07"], [0.5, 2.0, 0.8, "p08"], [1.0, 2.5, 0.9, "p09"], [1.5, 1.0, 1.0, "p10"], ]; const width = 800; const height = 600; const margin = {"top": 30, "bottom": 30, "right": 30, "left": 30}; const svg = d3.select("#scatter") .append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) ; const xScale = d3.scaleLinear() .domain([0, d3.max(dataset, function (d) { return d[0]; })]) .range([margin.left, margin.left + width]) ; const yScale = d3.scaleLinear() .domain([d3.max(dataset, function (d) { return d[1]; }), 0]) .range([margin.bottom, margin.bottom + height]) ; svg.append("g") .attr("class", "x_axis") .attr("transform", "translate(" + [0, height + margin.top].join(",") + ")" ) .call(d3.axisBottom(xScale).ticks(0.5) ); svg.append("g") .attr("class", "y_axis") .attr("transform", "translate(" + [margin.left, 0].join(",") + ")" ) .call(d3.axisLeft(yScale).ticks(0.5) ); const colorMax = 255; const colorMin = 80; const colorScale = d3.scaleLinear() .domain([d3.min(dataset, function (d) { return d[2]; }) , d3.max(dataset, function (d) { return d[2]; })]) .range([colorMin, colorMax]) ; const tooltip = d3.select("#scatter") .append("div") .style("position", "absolute") .style("text-align", "left") .style("background", "#ffffff") .style("border", "1px solid #000000") .style("padding", "10px") .style("opacity", 0) ; svg.append("g") .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", 10) .attr("fill", function (d) { return "rgba(0, 0, " + Math.round(colorScale(d[2])) + ", 0.8)"; }) .on("mouseover", function (e) { const d = e.target.__data__; console.log(e); tooltip .style("left", e.x + 30 + 'px') .style("top", e.y + 'px') .html( "id: " + d[3] + "" + "[" + d[0] + ", " + d[1] + "]" + "" + "value: " + d[2] ) .style("opacity", 1) ; }) .on("mouseout", function (d) { tooltip .style("opacity", 0) ; }) ; </script> </body> </html>


d3.js でシンプルな散布図を描画

2021-12-03 17:24:26 | javascript
d3.js でシンプルな散布図を描画する方法のメモ。
d3.js では左上が [0, 0] となるため、yScale では range を[margin.top, margin.top + height] にしています。
<html>
<head>

<title>d3.js test</title>
</head>
<body>
d3.js test
<script src="../d3.min.js"></script> <script type="text/javascript"> const dataset = [ // x, y, 値, ID [0.0, 0.0, 0.0, "p00"], [1.0, 2.0, 0.1, "p01"], [1.5, 4.0, 0.2, "p02"], [2.0, 1.5, 0.3, "p03"], [1.5, 4.0, 0.4, "p04"], [2.5, 3.5, 0.5, "p05"], [1.0, 4.0, 0.6, "p06"], [1.5, 3.5, 0.7, "p07"], [0.5, 2.0, 0.8, "p08"], [1.0, 2.5, 0.9, "p09"], [1.5, 1.0, 1.0, "p10"], ]; const width = 800; const height = 600; const margin = {"top": 60, "bottom": 30, "right": 30, "left": 60}; const xScale = d3.scaleLinear() .domain([0, d3.max(dataset, function (d) { return d[0]; })]) .range([margin.left, margin.left + width]) ; const yScale = d3.scaleLinear() .domain([d3.max(dataset, function (d) { return d[1]; }), 0]) .range([margin.top, margin.top + height]) ; const svg = d3.select("#scatter") .append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) ; svg.append("g") .attr("class", "x_axis") .attr("transform", "translate(" + [0, margin.top + height].join(",") + ")" ) .call(d3.axisBottom(xScale)) ; svg.append("g") .attr("class", "y_axis") .attr("transform", "translate(" + [margin.left, 0].join(",") + ")" ) .call(d3.axisLeft(yScale)) ; const colorMax = 255; const colorMin = 80; const colorScale = d3.scaleLinear() .domain([d3.min(dataset, function (d) { return d[2]; }) , d3.max(dataset, function (d) { return d[2]; })]) .range([colorMin, colorMax]) ; svg.append("g") .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", 7) .attr("fill", function (d) { return "rgba(" + Math.round(colorScale(d[2])) + ", 0, 0, 0.8)"; }) ; </script> </body> </html>