Plotting satellite orbit on python - python

I am trying to plot the orbit of a satellite around earth and the moon after using a RK4 numerical integration method for the orbital motions. But i dont quite know how display this or create the image. I kindly ask if anyone knows how this can be done. Below is the code section for the plotting;
from matplotlib import pyplot as plt
# We only plot the x, y components (view on the ecliptic plane)
x, y, v_x, v_y, t = Orbit(x_0, y_0, v_x0, v_y0, tmin, tmax, N)
kinetic_energy, potential_energy, total_energy = Energy(x,y,v_x,v_y)
# Set a dark background... since... space is dark
plt.style.use('dark_background')
# Create a figure and ax
fig, ax = plt.subplots(figsize=(12, 8))
# Create a yellow circle that represents the Sun, add it to the ax
Earth_circ = plt.Circle((0.0, 0.0), R_E, color='yellow', alpha=0.8)
ax.add_artist(Earth_circ)
# Plot the SSB movement
ax.plot(x, y, ls='solid', color='royalblue')
# Set some parameters for the plot, set an equal ratio, set a grid, and set
# the x and y limits
ax.set_aspect('equal')
ax.grid(True, linestyle='dashed', alpha=0.5)
# Set Axes limits to trajectory coordinate range, with some padding
xmin, xmax = min(x), max(x)
ymin, ymax = min(y), max(y)
dx, dy = xmax - xmin, ymax - ymin
PAD = 0.05
ax.set_xlim(xmin - PAD*dx, xmax + PAD*dx)
ax.set_ylim(ymin - PAD*dy, ymax + PAD*dy)
# Some labelling
ax.set_xlabel('X in Earths-Radius')
ax.set_ylabel('Y in Earths-Radius')
# Saving the figure in high quality
plt.tight_layout()
plt.savefig('orbit.png', dpi=300)
plt.show()

Related

How to get the line's label if multiple graphs have been plotted?

plt.plot(x, y, label = name1)
plt.plot(x, y, label = name2)
plt.plot(x, y, label = name3)
plt.show()
How to get the label when I click the line or better if I can get this information directly in the graph window like I get the x and y axis values on bottom right.
The fastest way would be to add a legend to your graph with plt.legend() right before plt.show()
For more interactivity, maybe try bokeh instead of matplotlib.
Not sure exactly what you are asking for but if you want to represent each line with a name, or the series of the x-values, you could use legend() and input a string or series name as label name in the plot-line:
plt.plot(x1, y, label = "name1") # Show the string name1
plt.plot(x2, y, label = x2) # Shows the array x2
plt.legend() # Displays the legends
If you want to add title or labels for the axis you could use:
plt.xlabel('X-axis Label')
plt.ylabel('Y-axis label')
plt.title('Title')
I am not sure if this is what you are looking for? But you can easily name your graphs by using the Legend. the first graph will be the first in your Legendlist. The important code is between the slash :-)
import matplotlib.pyplot as plt
import numpy as np
# Select length of axes and the space between tick labels
xmin, xmax, ymin, ymax = -10, 10, -10, 10
ticks_frequency = 1
# Plot points
fig, ax = plt.subplots(figsize=(10, 10))
#//////////////////////////////////////////////////////////////////////////////
# x range
x = np.arange(-5, 5., 0.025)
# f1
y1 = 3*x+4
f1 = ax.plot(x, y1, lw = 3, alpha = 0.5, color="blue")
# f2
y2 = 1*x+1
f2 = ax.plot(x, y2, lw = 3, alpha = 0.5, color="orange")
# f3
y3 = -2*x+8
f3 = ax.plot(x, y3, lw = 3, alpha = 0.5, color="red")
# legend
ax.legend(["Gerade 1", "Gerade 2", "Gerade 3"])
#//////////////////////////////////////////////////////////////////////////////
# Set identical scales for both axes
ax.set(xlim=(xmin-1, xmax+1), ylim=(ymin-1, ymax+1), aspect='equal')
# Set bottom and left spines as x and y axes of coordinate system
ax.spines['bottom'].set_position('zero')
ax.spines['left'].set_position('zero')
# Remove top and right spines
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
# Create 'x' and 'y' labels placed at the end of the axes
ax.set_xlabel('x', size=14, labelpad=-24, x=1.03)
ax.set_ylabel('y', size=14, labelpad=-21, y=1.02, rotation=0)
# Create custom major ticks to determine position of tick labels
x_ticks = np.arange(xmin, xmax+1, ticks_frequency)
y_ticks = np.arange(ymin, ymax+1, ticks_frequency)
ax.set_xticks(x_ticks[x_ticks != 0])
ax.set_yticks(y_ticks[y_ticks != 0])
# Create minor ticks placed at each integer to enable drawing of minor grid
# lines: note that this has no effect in this example with ticks_frequency=1
ax.set_xticks(np.arange(xmin, xmax+1), minor=True)
ax.set_yticks(np.arange(ymin, ymax+1), minor=True)
# Draw major and minor grid lines
ax.grid(which='both', color='grey', linewidth=1, linestyle='-', alpha=0.2)
# Draw arrows
arrow_fmt = dict(markersize=4, color='black', clip_on=False)
ax.plot((1), (0), marker='>', transform=ax.get_yaxis_transform(), **arrow_fmt)
ax.plot((0), (1), marker='^', transform=ax.get_xaxis_transform(), **arrow_fmt)
plt.show()

Matplotlib - Reversing label and line in legend

I'm trying to reverse the label and key columns in a matplotlib legend and I'm really struggling to even know where to start.
In a normal matplotlib legend the pattern is key, then label, like in the example below where it goes key (blue line), then label (First Line):
To match our company plotting style we plot things the reverse, i.e., label first then key (see the legend below). So the plot above would be First line, then the key (blue line).
The additional complication is that the keys should be in one column (so the align in one vertical column) regardless of the length of the label.
Well, there is the keyword markerfirst for this.
from matplotlib import pyplot as plt
import numpy as np
np.random.seed(1234)
n=7
fig, ax = plt.subplots()
ax.plot(np.arange(n), np.random.random(n), label="ABCDEF")
ax.plot(np.arange(n), np.random.random(n), label="G")
ax.legend(markerfirst=False)
plt.show()
Sample output
I would be tempted to write a standalone function that ignores ax.legend() entirely and instead draws a white box, the labels, and the markers where you need them. All the coordinates would be expressed in ax coordinates via transform=ax.transAxes to ensure a proper positioning and replace the locator keyword of ax.legend().
The following code will automatically cram all the artists found on the ax in the legend box boundaries that you defined. You might need to adjust the "padding" a bit.
Note that for some reason it does not work with lines of width 0 that only use a marker, but it shouldn't be an issue considering your question.
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
# Dummy data.
X = np.linspace(-5, +5, 100)
Y1 = np.sin(X)
Y2 = np.cos(X/3)
Y3 = Y2-Y1
Y4 = Y3*Y1
ax.plot(Y1, label="Y1")
ax.plot(Y2, label="Y2")
ax.plot(Y3, label="Y3", linestyle="--")
ax.plot(Y4, label="Y4", marker="d", markersize=4, linewidth=0)
fig.show()
def custom_legend(ax):
"""Adds a custom legend to the provided ax. Its labels are aligned
on the left and the markers on the right. Both are taken automatically
from the ax."""
handles, labels = ax.get_legend_handles_labels()
# Boundaries of your custom legend.
xmin, xmax = 0.7, 0.9
ymin, ymax = 0.5, 0.9
N = len(handles)
width = xmax-xmin
height = ymax-ymin
dy = height/N
r = plt.Rectangle((xmin, ymin),
width=width,
height=height,
transform=ax.transAxes,
fill=True,
facecolor="white",
edgecolor="black",
zorder=1000)
ax.add_artist(r)
# Grab the tiny lines that would be created by a call to `ax.legend()` so
# that we don't have to retrieve all the attributes ourselves.
legend = ax.legend()
handles = legend.legendHandles.copy()
legend.remove()
for n, (handle, label) in enumerate(zip(handles, labels)):
# Place the labels on the left of the legend box.
x = xmin + 0.01
y = ymax - n*dy - 0.05
ax.text(x, y, label, transform=ax.transAxes, va="center", ha="left", zorder=1001)
# Move a bit to the right and place the line artists.
x0 = (xmax - 1/2*width)
x1 = (xmax - 1/8*width)
y0, y1 = (y, y)
handle.set_data(((x0, x1), (y0, y1)))
handle.set_transform(ax.transAxes)
handle.set_zorder(1002)
ax.add_artist(handle)
custom_legend(ax)
fig.canvas.draw()

Pyplot: Contour lines that enclose a certain number of points (or a certain probability value) in a scatter plot?

I want to create a PDF from a scatter plot. This is the code I'm currently using:
data = np.column_stack((x, y))
nbins = 100
xmin = -0.5; xmax = 0.5; ymin = -5; ymax = 5
k = kde.gaussian_kde(data.T)
xi, yi = np.mgrid[xmin:xmax:nbins*1j, ymin:ymax:nbins*1j]
zi = k(np.vstack([xi.flatten(), yi.flatten()]))
fig, ax = plt.subplots(figsize=(5.5,4))
plt.pcolormesh(xi, yi, zi.reshape(xi.shape), shading='gouraud', cmap='Purples')
plt.contour(xi, yi, zi.reshape(xi.shape), levels = [0.2, 0.5, 0.7, 1, 1.5], linewidths=1, linestyles='dashed', cmap='viridis')
plt.xlabel('$x$')
plt.ylabel('$y$]')
plt.grid(True, linestyle='--')
ax.set_xlim(xmin, xmax)
ax.set_ylim(ymin, ymax)
fig.savefig('test.png', dpi=600)
plt.close(fig)
And this is the plot I'm getting from the code:
I have two questions about this:
It seems there's a problem with the PDFs since I can draw contour lines at levels 1 and 1.5 and since it's a PDF, values should be below 1.
How can I draw contour lines that enclose a certain number of points or at a certain probability level?
Data: x and y. (Format: npy.)
You can use:
plt.savefig('Testing.pdf', format='pdf')

how to set the grid when using pcolormesh

I am using pcolormesh to create a grid that overlaps a 2dhistogram.
import matplotlib.pyplot as plt
import numpy as np
import random
x = [random.randrange(1,161,1) for _ in range (10)]
y = [random.randrange(1,121,1) for _ in range (10)]
fig, ax = plt.subplots()
ax.set_xlim(0,160)
ax.set_ylim(0,120)
zi, yi, xi = np.histogram2d(y, x, bins=(50,120))
zi = np.ma.masked_equal(zi, 0)
ax.pcolormesh(xi, yi, zi, edgecolors='black')
scat = ax.scatter(x, y, s=2)
Although, this code only produces a grid that covers the outermost xy data points.
I'd like the grid to be constant with the set axes limits (x = 0,160), (y = 0,120). So The grid is constantly covering the plotted area. From 0,0 to 160,120.
I have tried to use the vmin, vmax function in pcolormesh. But this just produces a blank figure. I don't get an error code though?
ax.pcolormesh(xi, yi, zi, edgecolors='black', vmin = (0,0), vmax = (120,160))
Is there another way to extend the grid to the desired axes limits?
One problem is that the histogram2d function determines the bins itself if you use it like you do.
This means that both the offset and the width of your bins is unclear until runtime because they depend on your random points rather than on your axis limits. Now once the bins are found you could read back their shape and set an axis grid accordingly. But it's easier to create your own bins so you get a grid that spans the whole axis ranges.
Then you can set the edges of your bins as minor ticks and enable a grid on them.
Using the lines created by pcolormesh would work too but when using it you will get some lines that are thicker than others (this has to do with line positions falling between pixels). With axis grid this doesn't happen but some lines appear to cut through your bins. In the end it's a matter of taste which one you prefer. You can always play around with edgecolor and linewidth until pcolormesh shows a decent result.
import matplotlib.pyplot as plt
import numpy as np
import random
x = [random.randrange(1,161,1) for _ in range (10)]
y = [random.randrange(1,121,1) for _ in range (10)]
fig, ax = plt.subplots()
ax.set_xlim(0,160)
ax.set_ylim(0,120)
bins = [
np.linspace(*ax.get_xlim(), 120),
np.linspace(*ax.get_ylim(), 50)
]
# Note that I switched back to x, y and used zi.T later which I find
# more readable
zi, xi, yi = np.histogram2d(x, y, bins=bins)
zi = np.ma.masked_equal(zi, 0)
# Either use the next four lines for axis grid
ax.pcolormesh(xi, yi, zi.T)
ax.set_xticks(bins[0], minor=True)
ax.set_yticks(bins[1], minor=True)
ax.grid(True, which='minor')
# or use the next line to stick with edges drawn by pcolormesh
# ax.pcolormesh(xi, yi, zi.T, edgecolor='black')
scat = ax.scatter(x, y, s=2)

rotate the fill function of matplotlib in a figure

I am trying to make a three joint plot. The frame of one of the plots is rotated by 90 degrees with respect to the other and perpendicular to the axis of the other. So I can make a histogram plot in this frame but when I use kde and generate data and use fill to overlay to the hist it won't rotate.
import pylab as plt
import seaborn as sns
from scipy.stats import gaussian_kde
import numpy as np
from astroML.plotting import hist
from mpl_toolkits.axes_grid1 import make_axes_locatable
sns.set_style("ticks")
axScatter = plt.subplot(111)
xmin, xmax = x.min(), x.max()
ymin, ymax = y.min(), y.max()
# Peform the kernel density estimate
xx, yy = np.mgrid[xmin:xmax:100j, ymin:ymax:100j]
positions = np.vstack([xx.ravel(), yy.ravel()])
values = np.vstack([x, y])
kernel = gaussian_kde(values)
f = np.reshape(kernel(positions).T, xx.shape)
axScatter.set_xlim(xmin, xmax)
axScatter.set_ylim(ymin, ymax)
# Contourf plot
cfset = axScatter.contourf(xx, yy, f, cmap='Blues')
## Or kernel density estimate plot instead of the contourf plot
#ax.imshow(np.rot90(f), cmap='Blues', extent=[xmin, xmax, ymin, ymax])
# Contour plot
cset = axScatter.contour(xx, yy, f, colors='k')
# Label plot
axScatter.scatter(x, y, marker='o', s=1, alpha=0.2, color='k')
axScatter.set_aspect('auto')
axScatter.set_xlabel(r'$X$')
axScatter.set_ylabel(r'$Y$')
# create new axes on the right and on the top of the current axes.
divider = make_axes_locatable(axScatter)
axHistx = divider.append_axes("top", size=1.2, pad=0.1, sharex=axScatter)
axHisty = divider.append_axes("right", size=1.2, pad=0.1, sharey=axScatter)
# the scatter plot:
# histograms
kde = gaussian_kde(x)
X_plot = np.linspace(xmin, xmax, 1000)
X_dens = kde.evaluate(X_plot)
axHistx.fill(X_plot, X_dens, fc='#AAAAFF',alpha=0.2)
hist(x, bins='knuth', ax=axHistx, color='black', histtype='step', normed=True)
kde = gaussian_kde(y)
Y_plot = np.linspace(ymin,ymax, 1000)
Y_dens = kde.evaluate(Y_plot)
axHisty.fill(Y_plot, Y_dens, fc='#AAAAFF' ,alpha=0.2)
hist(y, bins='knuth', ax=axHisty, color='black', histtype='step', normed=True, orientation='horizontal')
How can I rotate the fill function in right panel?
You can use the fill_betweenx function of the axHisty axes to do this:
axHisty.fill_betweenx(Y_plot, Y_dens, color='#AAAAFF' ,alpha=0.2)
Note the fill_betweenx doesn't take fc as a kwarg, but does take color.
I modified the scatter_hist.py example from the matplotlib gallery to have histograms and fills in the same style as your plot, and used the fill_betweenx line above, to create this plot:

Categories

Resources