python - 在 plotly 中旋转标记

标签 python plot plotly bokeh

我正在尝试绘制苍蝇的轨迹。它由 x、y、theta(航向)和时间戳组成。我正在绘制所有点的散点图,三角形标记的方向传达了航向。我在这里需要的是根据 theta 值旋转标记。但是我无法找到任何方法来进行这种操作。

我不能只使用散点标记,我需要 0-360 的整个浮点范围。我可以在 bokeh 中做到这一点,但我还有其他关于交互性的问题,这些问题可以更好地管理。

enter image description here

最佳答案

您可以通过更改路径属性来改变 Plotly 标记的形状。可以访问每个轨迹的点 document.getElementsByClassName("points")[traceNumber].getElementsByClassName("point") 然后您可以设置路径属性,如下所示。每个标记都被一个三角形覆盖,该三角形根据矢量旋转到下一个点。

或者,您可以在布局中添加与 shapes 相同的路径,但您无法切换轨迹。

切换适用于此代码段,但当第一条轨迹被隐藏时,方向取自错误的轨迹。

enter image description here

//extract the points from a SVG path
function pointsFromPath(path) {
    var x = [];
    var y = [];
    var str_x = "";
    var str_y = "";
    for (var i = 0; i < path.length; i += 1) {
        if (path.substring(i, i + 1) === "M" || path.substring(i, i + 1) === "L") {
            str_x = path.substring(i + 2, path.length);
            str_x = str_x.substring(0, str_x.indexOf(" "));
            x.push(parseFloat(str_x));
            str_y = path.substring(i + 3 + str_x.length, path.length);
            str_y = str_y.substring(0, str_y.indexOf(" "));
            y.push(parseFloat(str_y));
        }
    }
    return [x, y];
}

//constructs a path from a path template and x and y array
function newPath(path, x, y) {
    var index = 0;
    var n_path = '';
    for (var i = 0; i < path.length; i += 1) {
        if (path.substring(i, i + 1) === "M" || path.substring(i, i + 1) === "L") {
            n_path += path.substring(i, i + 1);
            n_path += " ";
            n_path += x[index];
            n_path += " ";
            n_path += y[index];
            n_path += " ";
            index += 1;
        } else if (path.substring(i, i + 1) === "Z") {
            n_path += path.substring(i, i + 1);
        }
    }
    return n_path;
}
//rotates a simple SVG path
function rotatePath(path, angle) {
    var points = pointsFromPath(path);
    var x = points[0];
    var y = points[1];
    var new_x = 0;
    var new_y = 0;
    for (var i = 0; i < x.length; i += 1) {
        new_x = Math.cos(angle) * x[i] - Math.sin(angle) * y[i];
        new_y = Math.sin(angle) * x[i] + Math.cos(angle) * y[i];
        x[i] = new_x;
        y[i] = new_y;
    }
    return newPath(path, x, y);
}

//moves a simple SVG path
function movePath(path, cx, cy) {
    var points = pointsFromPath(path);
    var x = points[0];
    var y = points[1];
    for (var i = 0; i < x.length; i += 1) {
        x[i] += cx;
        y[i] += cy;
    }
    return newPath(path, x, y);
}

//reshape the scatter plot markers
function triangles(data, triangle) {
    var markers;
    var legends;
    var i = 0;
    var j = 0;
    var new_path = "";
    var points;
    for (j = 0; j < data.length; j += 1) {
        legends = document.getElementsByClassName("scatterpts")[j];
        legends.setAttribute("d", triangle);
        points = document.getElementsByClassName("points")
        if (j >= points.length) {
            break;
        }
        markers = points[j].getElementsByClassName("point");
        for (i = 0; i < data[j].x.length - 1; i += 1) {
            new_path = rotatePath(triangle, -Math.PI / 2 - Math.atan2(data[j].y[i + 1] - data[j].y[i], data[j].x[i + 1] - data[j].x[i]));
            new_path = movePath(new_path, data[j].x[i], data[j].y[i]);
            markers[i].setAttribute("d", new_path);
        }
        markers[i].setAttribute("d", new_path);
        
    }
}

//define the initial triangle
var size = 5;
var triangle = "M " + Math.sin(0) * size + " ";
triangle += Math.cos(0) * size + " L ";
triangle += Math.sin(Math.PI * 2 / 4) * size + " ";
triangle += Math.cos(Math.PI * 2 / 4) * size + " ";
triangle += "L ";
triangle += Math.sin(Math.PI * 6 / 4) * size + " ";
triangle += Math.cos(Math.PI * 6 / 4) * size + " ";
triangle += "Z";

//create some input data
var data = [];
var i = 0;
var j = 0;
var x = [[0, 1, 2, 3, 4, 5, 4, 3, 2, 1],
         [3, 2, 1, 0, 1, 2, 3 , 5]];
var y = [[0, 1, 2, 1, 0, 1, 2, 4.5, 1, 0],
         [0, 1, 2, 3, 4, 3, 2 , 4]];
var s_x;
var s_y;
var steps = 10;
var layout = {xaxis: {range: [-1, 5.5]},
              yaxis: {range: [-1, 5.5]}};
var myDiv = document.getElementById('myDiv');

//smooth the input data
for (i = 0; i < x.length; i += 1) {
    s_x = Smooth(x[i]);
    s_y = Smooth(y[i]);
    data.push({x: [],
               y: [],
               mode: "markers"
    });

    for (j = 0; j < (x[i].length - 1) * steps; j += 1) {
        data[i].x.push(s_x(j / steps));
        data[i].y.push(s_y(j / steps));
    }
}

Plotly.newPlot(myDiv, data);
triangles(data, triangle);
myDiv.on("plotly_relayout", function () {
    triangles(data, triangle);
});
myDiv.on("plotly_afterplot", function () {
    triangles(data, triangle);
});
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<script src="https://github.com/downloads/osuushi/Smooth.js/Smooth-0.1.7.js"></script>
<div id="myDiv"></div>

关于python - 在 plotly 中旋转标记,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45742264/

相关文章:

MATLAB 删除一个轴上的刻度,同时保留标签

r - 相当于 abline 在 plotly

Python 内部函数变量作用域

python - 在Python中添加新的字符串方法

python - 无论时态或形式如何匹配单词?

python - 多处理中的共享内存对象

r - 使用 r 设置 x 轴的间隔

python - 在四维 matplotlib 曲面中更改 Facecolors

javascript - 使用 Plotly.js 动态创建/删除/重新设计图形的最佳方式?

javascript - 在不重绘背景图的情况下以交互方式向 plotly R 中的子图添加点