Plotting circle diagram with rotary arrow - python-2.7

This is a diagram I clipped from a paper.
http://i11.tietuku.com/e1c71d1b84b37a51.png
I can plot the circle and the straight arrow, but how to plot the rotary arrow in specific angle?

You can draw a circle and a rotary arrow in matplotlib using sine/cosine, Arc and arrow:
import math
from matplotlib.patches import Arc
import matplotlib.pyplot as plt
ax = plt.axes()
x0, y0 = 0.5, 0.5
radius = 0.4
angle = 135
angle_rad = angle * math.pi / 180 # degrees to radians
# Draw circle
circle = plt.Circle((x0,y0), radius, color='red', fill=False)
fig = plt.gcf()
fig.gca().add_artist(circle)
# Draw radius arrow
head_length = 0.05
ax.arrow(x0, y0,
(radius - head_length) * math.cos(angle_rad),
(radius - head_length) * math.sin(angle_rad),
head_width=0.05, head_length=head_length, fc='k', ec='k')
# Draw arc with arrow.
arc_radius = radius / 4
arc = Arc((x0, y0),
arc_radius*2, arc_radius*2, # ellipse width and height
theta1=0, theta2=angle, linestyle='dashed')
ax.add_patch(arc)
arc_arrow_length = 0.03
arc_arrow_dx = arc_arrow_length * math.cos(angle_rad + math.pi / 2)
arc_arrow_dy = arc_arrow_length * math.sin(angle_rad + math.pi / 2)
ax.arrow(
x0 + arc_radius * math.cos(angle_rad) - arc_arrow_dx,
y0 + arc_radius * math.sin(angle_rad) - arc_arrow_dy,
# We want to define a vector,
# but we don't want to draw any line besides arrow head,
# so we make arrow "body" unnoticeable.
arc_arrow_dx * 0.000001,
arc_arrow_dy * 0.000001,
head_width=0.01,
head_length=0.03,
color='black')
plt.show()
Please note that this solution is not the cleanest, there is probably a better way to draw an arc and an arrow at once.
You may want to try FancyArrowPatch to draw a nice arrow.

Using plt.annotate, in the arrowprops parameter you can pass in a connectionstyle, which will define the curvature of the line you draw. Here's an example from the SciPy documentation. After that, all you need to do is set your linestyle and determine your beginning and ending points for each diagram.

Related

Drawing a circle with cos() sin(), no repeat pixel, no gaps?

I'm interested in drawing a circle of a vary radius using sin() and cos() functions.
Is there a golden rule to increment the radians so that there isn't multiple plots to the same location and no gaps in the circle drawn on a pixel based display?
x = cos(r) * radius
y = sin(r) * radius
r = r + s
My guess would be that s is something to do with dividing 2 × PI by the a number derived from the radius?
I'm sure this is either really simple or impossible due to the limitations of floating point calculations.
Thanks for your time
Anthony
The length of arc is simply s = r * delta_fi where r is the radius of the circle, fi is the angle and delta_fi is the change of the angle.
The projection of this arc to x-axis is delta_x = s * sin(fi) and to y-axis it is delta_y = s * cos(fi)
You want such delta_fi that either delta_x or delta_y is 1.
Obviously, the problem is symmetrical and we can solve it for fi from -45° to 45° and for delta y and then apply the same solution in other quadrants. We have:
r * delta_fi * cos(fi) = 1
Hence:
delta_fi = 1/cos(fi)/r
The coordinates of a circle can indeed be completely defined using the trigonometric functions sine and cosine:
x = cos(angle)
y = sin(angle)
If the radius is any other value than 1 (which happens to define the unit circle), the underlying principles of trigonometric functions still apply and, therefore, the following equations can be derived:
x = cos(angle) * radius
y = sin(angle) * radius
To implement this in Python (with the kind help of Numpy) all that is necessary in addition to what we have already defined is a suitable vector (or 1-dimensional array) for the angle, which will be evaluated by the function x and y.
import numpy as np
r = 2 # An arbitrary value for the radius
angle = np.linspace(0, 2*np.pi, 1000) # A vector covering all angles from
# 0 to 2*pi (the full circle in radians)
# with an arbitrary number of
# elements, 1000 in this example
x = np.cos(angle)*r
y = np.sin(angle)*r
On plotting this circle don't forget to adjust the size of the figure to a square, otherwise the circle will be distorted.
import matplotlib.pyplot as plt
plt.figure(figsize=(3, 3))
plt.plot(x, y)

If I have a line from point x1, y1 to x2, y2, how can I draw 2 lines coming from point x2, y2 at 45 degree angles to make an arrow?

I want an arrow to be drawn from the point the user clicks the mouse to the point he drags it to. The base line is the first line drawn in the code below. Now I would like 2 more short lines of distance d lines coming out of that point at 45 degrees to create an arrow pointing to the current mouse position. Those two lines are the second 2 lines drawn. drawLine() draws a line from the point at the first 2 values to the point at the 2nd 2 values. What I can't figure out is how to calculate the coordinates of the arrowLine variables I have in the code below.
double deltaX = mousePosX - mouseOnDownX;
double deltaY = mousePosY - mouseOnDownY;
double distance = sqrt(pow(deltaX, 2) + pow(deltaY, 2));
double angle = atan(deltaY / deltaX) * 180 / PI;
int arrowLineLength = 20;
int arrowLineAngle = 45;
screen->drawLine(mousePosX, mousePosY, mouseOnDownX,mouseOnDownY);
screen->drawLine(mousePosX, mousePosY, arrowLine1x,arrowLine1y);
screen->drawLine(mousePosX, mousePosY, arrowLine2x,arrowLine2y);
EDIT: To clarify, mouseOnDownX and mouseOnDownY are the coordinates of the mouse when the user originally presses the mouse button. mousePosX and mousePosY are the coordinates of the mouse at it's current position and is the point the arrow head lines should be coming out of.
co-ordinates are:
arrowLine1x=x+d*cos(atan(deltaY/deltaX)+45);
arrowLine1y=y+d*sin(atan(deltaY/deltaX)+45);
arrowLine2x=x+d*cos(atan(deltaY/deltaX)-45);
arrowLine2y=y+d*sin(atan(deltaY/deltaX)-45);
If you have a vector pointed in some direction and you want to rotate it clockwise by θ degrees, you can multiply it by this matrix:
|cos θ -sin θ|
|sin θ cos θ|
Therefore, if you have a direction vector pointing as (dx, dy), the vector formed by rotating it θ degrees clockwise is
dx' = dx cos θ - dy sin θ
dy' = dx sin θ + dy cos θ
In your case, you have a vector from the source to the destination. Therefore, a vector from the destination to the source would be given by (-deltaX, -deltaY). You can then get vectors 45 degrees to the left and right of this by plugging things into the above formula:
dx' = -deltaX cos θ + deltaY sin θ
dy' = -deltaX sin θ - deltaY cos θ
Use θ = π / 4 and θ = -π / 4 to get the 45° rotations in each direction. To ensure that the length of the line you draw is exactly d, you can normalize these vectors, then multiply by d. For example:
finalDX = dx' * d / sqrt(dx'^2 + dy'^2)
finalDY = dy' * d / sqrt(dx'^2 + dy'^2)
Hope this helps!

Fill Ellipses with Gradiant Color on Matlab

I have a code on matlab that allows me to plot a series of ellipses, what I am trying to do it to fill each of them with a gradiant color based on 'arcsin(b/a)' The number will go from 0° (straight line) to 90° (pure circle). So each ellipse will have a uniform color, but the colors of each ellipse will be different if that makes sense.
That's my code
clearvars -except data colheaders
data(:,9)=data(:,9)*pi/180; % Convers Column 9 (angle of rotation) in rad
data(:,6)=1196-data(:,6); % Reset the Y coordinate axis to bottom left
theta = 0 : 0.01 : 2*pi;
for i=1:size(data,1)
x = data(i,7)/2 * cos(theta) * cos(data(i,9)) - data(i,8)/2 * sin(theta) * sin(data(i,9)) + data(i,5);
y = data(i,8)/2 * sin(theta) * cos(data(i,9)) + data(i,7)/2 * cos(theta) * sin(data(i,9)) + data(i,6);
plot(x, y, 'LineWidth', 1);
hold on
% Columns (5,6) are the centre (x,y) of the ellipse
% Columns (7,8) are the major and minor axes (a,b)
% Column 9 is the rotation angle with the x axis
text(data(i,5),data(i,6),[num2str(i)]) % Assigns number to each ellipse
end
axis equal;
xlim([0 1592]);
ylim([0 1196]);
grid on;
Let me know if I need explain in a different way.
Thank you guys
Dorian

OpenGL - Creating a circle, change radius?

I must be the worst person on the planet when it comes to math because i can't figure out how to change this circle radius:
from math import *
posx, posy = 0,0
sides = 32
glBegin(GL_POLYGON)
for i in range(100):
cosine=cos(i*2*pi/sides)+posx
sine=sin(i*2*pi/sides)+posy
glVertex2f(cosine,sine)
I'm not entirely sure how or why this becomes a circle because the *2 confuses me a bit.
Note that this is done in Pyglet under Python2.6 calling OpenGL libraries.
Followed Example 4-1: http://fly.cc.fer.hr/~unreal/theredbook/chapter04.html
Clarification: This works, i'm interested in why and how to modify the radius.
This should do the trick :)
from math import *
posx, posy = 0,0
sides = 32
radius = 1
glBegin(GL_POLYGON)
for i in range(100):
cosine= radius * cos(i*2*pi/sides) + posx
sine = radius * sin(i*2*pi/sides) + posy
glVertex2f(cosine,sine)
But I would pick another names for variables. cosine and sine is not exactly what these variables are.
And as far as I see, you son't need a loop from 1 to 100 (or from 0 to 99, I'm not too good at Python), you just need a loop from 1 to sides.
Explanation:
When you calculate
x = cos (angle)
y = sin(angle)
you get a point on a circle with radius = 1, and centre in the point (0; 0) (because sin^2(angle) + cos^2(angle) = 1).
If you want to change a radius to R, you simply multiply cos and sin by R.
x = R * cos (angle)
y = R * sin(angle)
If you want to transfer the circle to another location (for example, you want the circle to have it's centre at (X_centre, Y_centre), you add X_centre and Y_xentre to x and y accordingly:
x = R * cos (angle) + X_centre
y = R * sin(angle) + Y_centre
When you need to loop through N points (in your case N = sides) on your circle, you should change the angle on each iteration. All those angles should be equal and their sum should be 2 * pi. So each angle should be equal to 2 * pi/ N. And to get i-th angle you multiply this value by i: i * 2 * pi / N.
math : P=pr^2=p*r*r= p*r*2 programming i*2*pi/sides
together : i = p i*2, *2=r^2 this should help you

rotate an image object along with the pointer in C

I have a C application where i have loaded my image(gif) object onto the screen. Now i wish the Image object to rotate on one axis along with my pointer.
Means wherever i move the pointer on the screen, my image should rotate from a fixed point...How do i do that?
I have seen formulae like
newx = cos(angle) * oldx - sin(angle) * oldy
newy = sin(angle) * oldx + cos(angle) * oldy
but it inputs angle also..but i dont have the angles... i have pointer coordinates... How do i make the object move according to the mouse pointer?
Seriously... You have learnt trigonometry in secondary school, right?
angle = arctan((pointerY - centerY) / (pointerX - centerX))
in C:
// obtain pointerX and pointerY; calculate centerX as width of the image / 2,
// centerY as heigth of the image / 2
double angle = atan2(pointerY - centerY, pointerX - centerX);
double newX = cos(angle) * oldX - sin(angle) * oldY
double newY = sin(angle) * oldX + cos(angle) * oldY
First of all, that formula is perfectly fine if your rotation is in 2D space. You cannot remove angle from your formula because rotation without an angle is meaningless!! Think about it.
What you really need is to learn more basic stuff before doing what you are trying to do. For example, you should learn about:
How to get the mouse location from your window management system (for example SDL)
How to find an angle based on the mouse location
How to draw quads with texture on them (For example using OpenGL)
How to perform transformation, either manually or for example using OpenGL itself
Update
If you have no choice but to draw straight rectangles, you need to rotate the image manually, creating a new image. This link contains all the keywords you need to lookup for doing that. However in short, it goes something like this:
for every point (dr,dc) in destination image
find inverse transform of (dr,dc) in original image, named (or, oc)
// Note that most probably or and oc are fractional numbers
from the colors of:
- (floor(or), floor(oc))
- (floor(or), ceil(oc))
- (ceil(or), floor(oc))
- (ceil(or), ceil(oc))
using bilinear interpolation, computing a color (r,g,b)
dest_image[dr][dc] = (r,g,b)
the angle you calculate between where the user clicks on the screen and the old coordinates.
e.g.
on screen you have a square
( 0,10)-----(10,10)
| |
| |
| |
( 0, 0)-----(10, 0)
and if the user clicks in say (15,5)
you can for example calculate the angle relative your square from either a corner or from the cross section of the square then just use the formulas that you already have for each coordinate of the square.