Forum Archive

Distance and bearing points in polar plot

robStacks

Hi all,

I am having a hard time implementing law of cosines in a polar plot.
Want to get the values of and print distance & beharing from blue to red.

import matplotlib.pyplot as plt
import numpy as np
from math import sqrt, cos

rangeblue = int(input("Range blue ? :"))
bearingblue = int(input("Bearing blue ? :"))
rangered = int(input("Range red ? :"))
bearingred = int(input("Bearing red ? :"))

thetablue= np.deg2rad(bearingblue)
thetared= np.deg2rad(bearingred)

fig = plt.figure()

ax = fig.add_subplot(111, projection='polar')

ax.scatter(thetablue,rangeblue)
ax.scatter(thetared,rangered, color='r')

ax.set_theta_direction(-1)
ax.set_rmax(120)
ax.set_theta_zero_location('N')
ax.set_title("Plot", va='bottom')

plt.show()

Thx in advance for any help on this.

Regards,

Robert.

JonB

Are you having trouble with the above code? Or are you then trying to compute the distances?

The easiest way to compute distance would be to convert (theta,r) to (x,y) then use standard way to computing distance (or use a vector class that lets you compute length directly)

See for example
https://stackoverflow.com/questions/20924085/python-conversion-between-coordinates

robStacks

Hi thx for the tip but i want to use degrees and distance for this one.
I am trying to implement this formula to get the distance and bearing in degrees from blue point to red point.

a^2 + b^2 - 2*a*b*cos(c) 
OR
c = sqrt(a^2 + b^2 - 2*a*b*cos(c))

But i keep getting errors and or getting bad results with non Sharp angels.

Any ideas?

stephen

@robStacks this is what i use for my game development..


def Dist(pos1, pos2):
    ax, ay = pos1
    bx, by = pos2
    dx = pow((bx-ax), 2)
    dy = pow((by-ay), 2)
    dist=sqrt(dx+dy)
    return dist

def Angle(pos1, pos2):
    dx, dy = pos1[0]-pos2[0], pos1[1]-pos2[1]
    angle = degrees(atan2(float(pos1[1]-pos2[1]), float(pos1[0]-pos2[0])))
    angle += 90 # added 90 deg o that topcenter is zero
    if angle < 0:
        angle += 360
    return angle

robStacks

Stephen, i might try and overlay an xy grid and use that code thx!

mikael

@robStacks, PyPi is full of vector classes, mine is here. You can use it as shown below, or reference the code for inspiration.

from vector import Vector

rangeblue = int(input("Range blue:"))
bearingblue = int(input("Bearing blue:"))
rangered = int(input("Range red:"))
bearingred = int(input("Bearing red:"))

blue = Vector(rangeblue, 0)
blue.degrees = bearingblue

red = Vector(rangered, 0)
red.degrees = bearingred

delta = red - blue

print('Distance:', delta.magnitude)
print('Bearing:', delta.degrees)
stephen

@robStacks ☝🏻☝🏻☝🏻☝🏻☝🏻πŸ’ͺ🏻

robStacks

Works like a charm thx for the help guys!!
Just need to round and substract negatieve degrees from 360.
But thats easy...πŸ˜ŽπŸ‘πŸ»

robStacks

Sorry for my noobisme but this is my first time coding python.
I trying to integrate the above code into sketch.py demo code below.
I can't get it to be printed & plotted into (ui.View) so i can draw onto it.

'''
A very simple drawing 'app' that demonstrates
custom views and saving images to the camera roll.
'''

import ui
import photos
import console
import matplotlib.pyplot as plt
import numpy as np
from vector import Vector

# The PathView class is responsible for tracking
# touches and drawing the current stroke.
# It is used by SketchView.

class PathView (ui.View):
    def __init__(self, frame):
        self.frame = frame
        self.flex = 'WH'
        self.path = None
        self.action = None

    def touch_began(self, touch):
        x, y = touch.location
        self.path = ui.Path()
        self.path.line_width = 1
        self.path.line_join_style = ui.LINE_JOIN_ROUND
        self.path.line_cap_style = ui.LINE_CAP_ROUND
        self.path.move_to(x, y)

    def touch_moved(self, touch):
        x, y = touch.location
        self.path.line_to(x, y)
        self.set_needs_display()

    def touch_ended(self, touch):
        # Send the current path to the SketchView:
        if callable(self.action):
            self.action(self)
        # Clear the view (the path has now been rendered
        # into the SketchView's image view):
        self.path = None
        self.set_needs_display()

    def draw(self):
        if self.path:
            self.path.stroke()

# The main SketchView contains a PathView for the current
# line and an ImageView for rendering completed strokes.
# It also manages the 'Clear' and 'Save' ButtonItems that
# are shown in the title bar.

class SketchView (ui.View):
    def __init__(self, width=1024, height=1024):
        self.bg_color = 'white'
        iv = ui.ImageView(frame=(0, 0, width, height))
        pv = PathView(frame=self.bounds)
        pv.action = self.path_action
        self.add_subview(iv)
        self.add_subview(pv)
        save_button = ui.ButtonItem()
        save_button.title = 'Save Image'
        save_button.action = self.save_action
        clear_button = ui.ButtonItem()
        clear_button.title = 'Clear'
        clear_button.tint_color = 'red'
        clear_button.action = self.clear_action
        self.right_button_items = [save_button, clear_button]
        self.image_view = iv

    def path_action(self, sender):
        path = sender.path
        old_img = self.image_view.image
        width, height = self.image_view.width, self.image_view.height
        with ui.ImageContext(width, height) as ctx:
            if old_img:
                old_img.draw()
            path.stroke()
            self.image_view.image = ctx.get_image()

    def clear_action(self, sender):
        self.image_view.image = None

    def save_action(self, sender):
        if self.image_view.image:
            # We draw a new image here, so that it has the current
            # orientation (the canvas is quadratic).
            with ui.ImageContext(self.width, self.height) as ctx:
                self.image_view.image.draw()
                img = ctx.get_image()
                photos.save_image(img)
                console.hud_alert('Saved')
        else:
            console.hud_alert('No Image', 'error')

#---------------------------------------integrate into sketch.py

        bearingblue = int(input("Bearing blue:"))
        rangeblue = int(input("Range blue:"))

        bearingred = int(input("Bearing red:"))
        rangered = int(input("Range red:"))

        blue = Vector(rangeblue, 0)
        blue.degrees = bearingblue

        red = Vector(rangered, 0)
        red.degrees = bearingred

        delta = red - blue

        print('Distance:', delta.magnitude)
        print('Bearing:', delta.degrees)

        thetablue= np.deg2rad(bearingblue)
        thetared= np.deg2rad(bearingred)

        fig = plt.figure()

        ax = fig.add_subplot(111, projection='polar')

        ax.scatter(thetablue,rangeblue)
        ax.scatter(thetared,rangered, color='r')

        ax.set_theta_direction(-1)
        """ax.set_rmax(120)"""
        ax.set_theta_zero_location('N')
        ax.set_title("Plot", va='bottom')

        plt.show()  

#--------------------------------------------       

# We use a square canvas, so that the same image
# can be used in portrait and landscape orientation.
w, h = ui.get_screen_size()
canvas_size = max(w, h)

sv = SketchView(canvas_size, canvas_size)
sv.name = 'Sketch'
sv.present('fullscreen')


Do i need to make it a class to be able to do this?

Thx in advance for any pointers.

Regards,

Robert.

robStacks

I can't seem to find out what the error is about in line 8 & 9
Invalid literal for int() with base 10?

import matplotlib.pyplot as plt

bearing = list()
range = list()
lines = [line.rstrip('\n') for line in open('waypoints.txt')]
for line in lines:
    stringElement = str.split(line, " ")
    bearing = int(stringElement[0])
    range = int(stringElement[1])

    bearing.append(bearing)
    range.append(range)

ax = plt.subplot(111, projection='polar')

#Plot points
plt.polar(bearings, ranges)

#Plot lines
#plt.polar(bearings, ranges)

ax.set_theta_direction(-1)
ax.set_rmax(120)
ax.set_theta_zero_location('N')
ax.set_title("Plot", va='bottom')

plt.show()

What am i doping wrong here?

Thx in advance for the help!

Regards,

Robert.

stephen

@robStacks said:

I can't seem to find out what the error is about in line 8 & 9
Invalid literal for int() with base 10?

```
import matplotlib.pyplot as plt

bearing = list()
range = list()
lines = [line.rstrip('\n') for line in open('waypoints.txt')]
for line in lines:
stringElement = str.split(line, " ")
bearing = int(stringElement[0])
range = int(stringElement[1])

bearing.append(bearing)
range.append(range)

ax = plt.subplot(111, projection='polar')

Plot points

plt.polar(bearing, range)

Plot lines

plt.polar(angles, values)

ax.set_theta_direction(-1)
ax.set_rmax(120)
ax.set_theta_zero_location('N')
ax.set_title("Plot", va='bottom')

plt.show()
```
What am i doping wrong here?

Thx in advance for the help!

Regards,

Robert.

i really feel like you can only get float from string then you can float to int ind i believe split is called incorrectly try

```python

stringElement = line.split(" ")
bearing = int(float(stringElement[0]))
range = int(float(stringElement[1]))

robStacks

Hmmm closer but Now i get a sintax error strangly onlusten in line 9😩

stephen

@robStacks said:

Hmmm closer but Now i get a sintax error strangly onlusten in line 9😩

here you go buddy 😁

i had a min to look at it and there was a few spelling and syntax issues. the way you used str.split felt like C++ or C# is that what you are coming from?

in waypoints.txt:

50 50
100 100
150 150

Then i ran:


import matplotlib.pyplot as plt

bearings = list()   # changed bearing β‡’ bearings
ranges = list()     # changed range β‡’ ranges
lines = [line.rstrip('\n') for line in open('waypoints.txt')]
for line in lines:
    # changed str.split(line, " ") β‡’ line.split(" ")
    stringElement = line.split(" ") 
    # Added float parse before int
    bearing = int(float(stringElement[0])) 
    # Added float parse before int
    range = int(float(stringElement[1]))    

    # changed bearing β‡’ bearings
    bearings.append(bearing)
    # changed range β‡’ ranges
    ranges.append(range)        

ax = plt.subplot(111, projection='polar')

#Plot points
plt.polar(bearings, ranges)

#Plot lines
#plt.polar(bearings, ranges)

ax.set_theta_direction(-1)
ax.set_rmax(120)
ax.set_theta_zero_location('N')
ax.set_title("Plot", va='bottom')

plt.show()

Output:
img

robStacks

Hi stephen thx for helping me out with this m8!!!
I have very little coding experience python is the deepest ever.
But i figured it is most easy to get into and figure out and commonly used.

Implemented your corrections but sadly still errors cant convert string to flaot this time in 10
I think maybe my pythonista installment is corrupted cause it does run with you

import matplotlib.pyplot as plt

bearings = list()   # changed bearing β‡’ bearings
ranges = list()     # changed range β‡’ ranges
lines = [line.rstrip('\n') for line in open('waypoints.txt')]
for line in lines:
    # changed str.split(line, " ") β‡’ line.split(" ")
    stringElement = line.split(" ") 
    # Added float parse before int
    bearing = int(float(stringElement[0]))
    # Added float parse before int
    range = int(float(stringElement[1])) 

    # changed bearing β‡’ bearings
    bearings.append(bearing)
    # changed range β‡’ ranges
    ranges.append(range)        

ax = plt.subplot(111, projection='polar')

#Plot points
plt.polar(bearings, ranges, 'k.', zorder=3)

#Plot lines
#plt.polar(bearings, ranges)

ax.set_theta_direction(-1)
ax.set_rmax(120)
ax.set_theta_zero_location('N')
ax.set_title("Plot", va='bottom')

plt.show()
mikael

@robStacks, more likely your input file has some non-printable characters or wrong line breaks.

Try printing out the strings and their len() before trying the conversion to int.

(float is not relevant if you know that you have strings of ints.)

robStacks

Thx again guys i'm not troubleling any more brain with that monster of a code.
Solved it with numpy
So much easier😎

import matplotlib.pyplot as plt
import numpy  as np

data = np.loadtxt('waypoints.txt')


theta = data[:, 0]
r = data[:, 1]

ax = plt.subplot(111, projection='polar')

plt.polar (theta, r)

ax.set_theta_direction(-1)
ax.set_rmax(120)
ax.set_theta_zero_location('N')
ax.set_title("Plot", va='bottom')

plt.show()
stephen

@robStacks your welcome. im glad you found a better way for yourself that means your learning what works for you and that will come in time. two things real fast..

first, when you post code are you using three back ticks and language or just ticks? i noticed your formatting is off.. should be like this


     ```python

its not a huge deal but to help yourlelf keep a "coding style" consistant its nessesary to build the discipline πŸ€“


second i know you have moved on but i feel this is a good learning opprotunitynfor yourself and this is because i feel its an easy fix and one that you will need to remember..

inside your waypoints.txt file, like @mikael had asked., what is your output? i feel there might be a , in there since your having a base 10 issue. if you look at mine again you will see my file shows

50 50
100 100
150 150

feel there is good chance this was the issue 🀠

robStacks

Yeah it is steep learning for me atm and format is also one of those things i need to learn.
Also i was fiddling around in that code so much to make it work that format got messed.

My textfile is just as your two coloms sep. by one space still use the same now.

18 50
17 60
15 40
12 40
18 50
robStacks

Next problemπŸ˜…

Manager to integrate the plot into sketch.py.
But i need to constrain the placing of the plot image.
It jumps to the right halfway out the screen soon as drawing starts

'''
A very simple drawing 'app' that demonstrates
custom views and saving images to the camera roll.
'''

import ui
import photos
import console
import matplotlib.pyplot as plt
import numpy as np
from io import BytesIO

# The PathView class is responsible for tracking
# touches and drawing the current stroke.
# It is used by SketchView.

class PathView (ui.View):
    def __init__(self, frame):
        self.frame = frame
        self.flex = 'WH'
        self.path = None
        self.action = None

    def touch_began(self, touch):
        x, y = touch.location
        self.path = ui.Path()
        self.path.line_width = 1
        self.path.line_join_style = ui.LINE_JOIN_ROUND
        self.path.line_cap_style = ui.LINE_CAP_ROUND
        self.path.move_to(x, y)

    def touch_moved(self, touch):
        x, y = touch.location
        self.path.line_to(x, y)
        self.set_needs_display()

    def touch_ended(self, touch):
        # Send the current path to the SketchView:
        if callable(self.action):
            self.action(self)
        # Clear the view (the path has now been rendered
        # into the SketchView's image view):
        self.path = None
        self.set_needs_display()

    def draw(self):
        if self.path:
            self.path.stroke()


data = np.loadtxt('waypoints.txt')


theta = data[:, 0]
r = data[:, 1]

ax = plt.subplot(111, projection='polar')

plt.polar (theta, r)

ax.set_theta_direction(-1)
ax.set_rmax(120)
ax.set_theta_zero_location('N')
ax.set_title("", va='bottom')

b = BytesIO()
plt.savefig(b)
bg = ui.Image.from_data(b.getvalue())

"""

img_view = ui.ImageView(background_color='white')
img_view.content_mode = ui.CONTENT_SCALE_ASPECT_FIT
img_view.image = bg
img_view.present()

"""


# The main SketchView contains a PathView for the current
# line and an ImageView for rendering completed strokes.
# It also manages the 'Clear' and 'Save' ButtonItems that
# are shown in the title bar.

class SketchView (ui.View):
    def __init__(self, width=1024, height=1024):
        self.bg_color = 'white'
        iv = ui.ImageView(frame=(0, 0, width, height))
        iv.image = bg
        iv.content_mode = ui.CONTENT_SCALE_ASPECT_FIT
        pv = PathView(frame=self.bounds)
        pv.action = self.path_action
        self.add_subview(iv)
        self.add_subview(pv)
        save_button = ui.ButtonItem()
        save_button.title = 'Save Image'
        save_button.action = self.save_action
        clear_button = ui.ButtonItem()
        clear_button.title = 'Clear'
        clear_button.tint_color = 'red'
        clear_button.action = self.clear_action
        self.right_button_items = [save_button, clear_button]
        self.image_view = iv

    def path_action(self, sender):
        path = sender.path
        old_img = self.image_view.image
        width, height = self.image_view.width, self.image_view.height
        with ui.ImageContext(width, height) as ctx:
            if old_img:
                old_img.draw()
            path.stroke()
            self.image_view.image = ctx.get_image()

    def clear_action(self, sender):
        self.image_view.image = None

    def save_action(self, sender):
        if self.image_view.image:
            # We draw a new image here, so that it has the current
            # orientation (the canvas is quadratic).
            with ui.ImageContext(self.width, self.height) as ctx:
                self.image_view.image.draw()
                img = ctx.get_image()
                photos.save_image(img)
                console.hud_alert('Saved')
        else:
            console.hud_alert('No Image', 'error')


# We use a square canvas, so that the same image
# can be used in portrait and landscape orientation.
w, h = ui.get_screen_size()
canvas_size = max(w, h)

sv = SketchView(canvas_size, canvas_size)
sv.name = 'Sketch'
sv.present('fullscreen')



ccc

range is a builtin in Python so it would be better to use a different variable name.

robStacks

@ccc
Ok thx for pointing that out to me i will chance it.πŸ‘πŸ»