使用matplotlib绘制机器人的xy坐标

时间:2017-07-16 20:40:31

标签: python matplotlib plot

我是matplotlib的新手,我正在努力学习这里的工作。

我在一段时间内拥有机器人的XY坐标,我想绘制这些点以显示机器人的运动。下面的代码(这可能是其他堆栈溢出专家的慷慨)提供了坐标的散点图。但是,我真的只想要最后30个条目。每个坐标都来自视频帧。视频是每秒30帧。我想绘制最后一秒,以便我可以想象运动。绘制的每个坐标应在1/30秒后消失。

说coords列表有1800个点,代表60秒的数据。我想从列表的开头绘制,每1/30秒绘制一个点,当绘图上的点数达到30时,在绘制第31个索引之前,从绘图中删除第0个索引点,因此从coords列表的每个连续点,直到结束。我认为这将模拟机器人正在移动,在最后1秒内留下其点的踪迹。

我不知道如何绘制一个点,并在绘制新点之后让它在一段时间后从帧中消失。这将模拟一个动作。

# read_data() returns a list of tuples of xy coordinates
coords = read_data()

x_list = [int(pt[0]) for pt in coords]
y_list = [int(pt[1]) for pt in coords]
x_min, x_max = min(x_list), max(x_list)
y_min, y_max = min(y_list), max(y_list)

fig=plt.figure()
ax1 = fig.add_subplot(111)
ax1.add_patch(  # draw the bounday of the robot movements based on the min and max of coordinates
    patches.Rectangle(
        (x_min, y_min),  # (x,y)
        x_max - x_min,  # width
        y_max - y_min,  # height
        linewidth=0.1,
        fill=False
    )
)
ax1.plot(x_list, y_list, 'or', linewidth=0, markersize=0.2)  # plot the whole set

#  what I really need is just the last 30 entries; each entry comes in 1/30th of a second in actual env

1 个答案:

答案 0 :(得分:0)

我最近遇到了类似的问题,因为我需要说明一些运动跟踪数据。我以为您以另一种方式解决了这个问题(恭喜!),但是为了后代的缘故,将其保留在这里。

我最终将其与Dash(https://plotly.com/dash/)配合使用。

如果将数据框“ df”中的值替换为x和y,则应该具有可以执行您所要求的功能(我认为)。如果您用数据替换了列表x和列表y的内容,那么您应该能够获得所需的内容。

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

import pandas as pd
import numpy as np
import random

# defining the number of steps
n = 3000

#creating two arrays for containing x and y coordinate -- these are the lists you need to change
#of size equals to the number of size and filled up with 0's
x = 100 + np.zeros(n)
y = 100 + np.zeros(n)

# filling the coordinates with random variables
for i in range(1, n):
    val = random.randint(1, 4)
    if val == 1:
        x[i] = x[i - 1] + 1
        y[i] = y[i - 1]
    elif val == 2:
        x[i] = x[i - 1] - 1
        y[i] = y[i - 1]
    elif val == 3:
        x[i] = x[i - 1]
        y[i] = y[i - 1] + 1
    else:
        x[i] = x[i - 1]
        y[i] = y[i - 1] - 1

df = {'X': x, 'Y': y, 'Sample no.': [ind+1 for ind, x in enumerate(x)]}

indx=[ind for ind, x in enumerate(df['Y'])]

time_df = pd.DataFrame({"time": [0], "df_len": [len(df['X'])]})

def df_cond(series, last_n, tail):
    if last_n < tail:
        s = series[0: last_n]
    else:
        s = series[(last_n-tail): last_n]

    return s

def change(dataframe, size):

    try:
        dataframe['time'][0] = dataframe['time'][0] + int(size)
        return dataframe['time'][0]

    except:
        return dataframe['time'][0]

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

app.layout = html.Div([

    html.Div([

        html.Div([
            dcc.Input(id='auto_speed', value=1, type='number'),
            ], className="two columns"),

        html.Div([
            dcc.Input(id='trail', value=100, type='number'),
            ], className="two columns"),

        html.Div([
            dcc.Input(id='man_start', value=0, type='number'),
            ], className="two columns"),

        html.Div([
            dcc.Input(id='man_end', value=0, type='number'),
            ], className="two columns"),
        ], className="row"),


    html.Div([
        html.Div([
            html.Div(id='auto_description'),
            ], className="six columns"),

        html.Div([
            html.Div(id='man_description')
            ], className="six columns"),
        ], className="row"),

    dcc.Interval(
            id='interval-component',
            interval=1*1000, # in milliseconds
            n_intervals=0
        ),

    html.Div([
        html.Div([
            dcc.Graph(id='behaviour', style={'width': 950, 'height': 950}, ),
            ], className="six columns"),

        html.Div([

            dcc.Graph(
                id='behaviour_full',
                style={'width': 950, 'height': 950},
                figure={
                    'data': [
                        dict(

                            x=df['X'],
                            y=df['Y'],

                            hovertext="xs and ys",
                            hoverinfo="text",
                            showlegend = True,
                            name = "Sample nr: {} - {} of {}".format(0, len(df['X']), len(df['X'])),
                            mode='markers',
                            opacity=0.7,
                            marker={
                                'size': 5,
                                'line': {'width': 0.5, 'color': 'white'}
                            }

                        )
                    ],

                    'layout': dict(
                        xaxis={'type': 'linear', 'title': 'x-positions', 'range': [0,200]},
                        yaxis={'type': 'linear','title': 'y-positions', 'range': [0,200]},
                        hovermode='closest',
                        transition = {'duration': 1}
                    )

                })

                ], className="six columns"),

        ], className="row"),

    # Hidden div inside the app that stores the intermediate value
    html.Div(id='intermediate-value', style={'display': 'none'})
])

#callbacks are activated, when they receive input -- so a callback including an interval-component, will update at the interval-component update-rate
@app.callback(
    Output('intermediate-value', 'children'),

    [Input('interval-component', 'n_intervals'),
    Input('auto_speed', component_property='value'),
    Input(component_id='man_start', component_property='value'),
    Input(component_id='man_end', component_property='value')]
)
def clean_data(value, size, man_start, man_end):
    if man_start == -1:
        time_df['time'][0] = man_end
        print("zeroed")
        return time_df['time'][0]

    elif type(man_start) is int and type(man_end) is int and (man_end - man_start) > 0:
        return change(time_df, 0)

    else:
        return change(time_df, size)

@app.callback(
    Output(component_id='behaviour', component_property='figure'),

    [Input(component_id='auto_speed', component_property='value'),
    Input('intermediate-value', 'children'),
    Input(component_id='trail', component_property='value'),
    Input(component_id='man_start', component_property='value'),
    Input(component_id='man_end', component_property='value'),]
)
def update_figure(interval, last_n, tail, man_start, man_end):

    if type(man_start) is int and type(man_end) is int and (man_end - man_start) > 0:
        return {
            'data': [
                dict(

                    x=df['X'][man_start: man_end],
                    y=df['Y'][man_start: man_end],

                    hovertext=["X: {}<br>Y: {}<br>Sample: {}".format(df['X'][man_start: man_end][i], df['Y'][man_start: man_end][i], indx[i]+1) for i in indx[man_start: man_end]],
                    hoverinfo="text",
                    showlegend = True,
                    name = "Sample nr: {} - {} of {} <br>{}".format(man_start, man_end, len(df['X']), interval),
                    mode='markers',
                    opacity=0.7,
                    marker={
                        'size': 5,
                        'line': {'width': 0.5, 'color': 'white'}
                    }

                )
            ],

            'layout': dict(
                xaxis={'type': 'linear', 'title': 'x-positions', 'range': [0,200]},
                yaxis={'type': 'linear','title': 'y-positions', 'range': [0,200]},
                hovermode='closest',
                uirevision= 'dataset',
                transition = {'duration': 1}
            )

        }

    else:

        if last_n is None:
            last_n = 0

        return {
            'data': [
                dict(
                    x=df_cond(df['X'], last_n, tail),
                    y=df_cond(df['Y'], last_n, tail),

                    hovertext=["X: {}<br>Y: {}<br>Sample: {}".format(df['X'][i-1], df['Y'][i-1], df['Sample no.'][i-1]) for i in df_cond(df['Sample no.'], last_n, tail)],
                    hoverinfo="text",
                    showlegend = True,
                    name = "Sample nr: {} - {} of {} <br>{}".format(last_n - len(df_cond(df['X'], last_n, tail))+1, last_n, len(df['X']), interval),
                    mode='markers',
                    opacity=0.7,
                    marker={
                        'size': 5,
                        'line': {'width': 0.5, 'color': 'white'}
                    }

                )
            ],

            'layout': dict(
                xaxis={'type': 'linear', 'title': 'x-positions', 'range': [0,200]},
                yaxis={'type': 'linear','title': 'y-positions', 'range': [0,200]},
                hovermode='closest',
                uirevision= 'dataset',
                transition = {'duration': 1}
            )

        }



@app.callback(
    Output(component_id='auto_description', component_property='children'),

    [Input(component_id='auto_speed', component_property='value'),
    Input('interval-component', 'n_intervals'),
    Input(component_id='man_start', component_property='value'),
    Input(component_id='man_end', component_property='value'),
    Input(component_id='trail', component_property='value')]
)
def update_output_div(input_value, n_intervals, man_start, man_end, tail):

    if man_start == -1:
        return ' Auto sample index set to: {}'.format(man_end)

    elif type(man_start) is int and type(man_end) is int and (man_end - man_start) > 0:
        return ' Manual values being used.'

    else:
        if tail > time_df['time'][0]:
            return ' Automatic slice: {} - {}'.format(0, time_df['time'][0])

        else:
            return ' Automatic slice: {} - {}'.format(time_df['time'][0]-tail, int(time_df['time'][0]))

@app.callback(
    Output(component_id='man_description', component_property='children'),

    [Input(component_id='man_start', component_property='value'),
    Input(component_id='man_end', component_property='value')]
)
def update_output_div(start_val, end_val):
    if start_val is None:
        return ' Using auto slice'

    elif start_val == -1:
        return ' Setting auto sample index to: {}'.format(end_val)

    elif end_val - start_val  > 0:
        return ' Manual slice: {} - {}'.format(start_val, end_val)

    else:
        return ' Using auto slice'

if __name__ == '__main__':
    app.run_server(debug=True)

您可以通过在终端中的“在http://(...)上运行”行中输入地址来查看插图。

适当的让点从框架中消失-在此脚本中所做的基本上只是重新绘制示例数据的新部分。我相当确定我的解决方案效率很低。但这确实满足了我的需要。