I wanted to perform arithmetic operations on dates so i converted these dates
idx_1 = 2017-06-07 00:00:00
idx_2 = 2017-07-27 00:00:00
to floats using,
x1 = time.mktime(idx_1.timetuple()) # returns float of dates
>>> 1496773800.0
x2 = time.mktime(idx_2.timetuple())
>>> 1501093800.0
y1 = 155.98
y2 = 147.07
Am using the following code to plot:
import datetime as dt
import time
import numpy as np
import matplotlib.pyplot as plt
x = [x1, x2]
y = [y1, y2]
Difference = x2 - x1 #this helps to end the plotted line at specific point
coefficients = np.polyfit(x, y, 1)
polynomial = np.poly1d(coefficients)
# the np.linspace lets you set number of data points, line length.
x_axis = np.linspace(x1, x2 + Difference, 3) # linspace(start, end, num)
y_axis = polynomial(x_axis)
plt.plot(x_axis, y_axis)
plt.plot(x[0], y[0], 'go')
plt.plot(x[1], y[1], 'go')
plt.show()
Which plots:
How to make matplotlib to plot the actual dates on x axis instead of floats?
Any kind of Help is Greatly Appreciated.
Starting with datetime objects you may use matplotlib's date2num and num2date functions to convert to and from numerical values. The advantage is that the numerical data is then understood by matplotlib.dates locators and formatters.
import datetime
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates
idx_1 = datetime.datetime(2017,06,07,0,0,0)
idx_2 = datetime.datetime(2017,07,27,0,0,0)
idx = [idx_1, idx_2]
y1 = 155.98
y2 = 147.07
x = matplotlib.dates.date2num(idx)
y = [y1, y2]
Difference = x[1] - x[0] #this helps to end the plotted line at specific point
coefficients = np.polyfit(x, y, 1)
polynomial = np.poly1d(coefficients)
# the np.linspace lets you set number of data points, line length.
x_axis = np.linspace(x[0], x[1] + Difference, 3) # linspace(start, end, num)
y_axis = polynomial(x_axis)
plt.plot(x_axis, y_axis)
plt.plot(x[0], y[0], 'go')
plt.plot(x[1], y[1], 'go')
loc= matplotlib.dates.AutoDateLocator()
plt.gca().xaxis.set_major_locator(loc)
plt.gca().xaxis.set_major_formatter(matplotlib.dates.AutoDateFormatter(loc))
plt.gcf().autofmt_xdate()
plt.show()
Related
Good morning,
is it possible in matplotlib to get a secondary xy axis in the same graph?
I am not looking for twinx() or twiny().
I have two data sets: x1, y1 and x2, y2, which i both want to plot in the same graph.
I would like to plot the first data set in the normal axes: ax1.plot(x1, y1).
The second y-axis should be located on the right and the second x-axis should be located on the top.
But how do i set this up?
Kind regards
Thomas
Taken from matplotlib secondary_axis docu:
import matplotlib.pyplot as plt
import numpy as np
import datetime
import matplotlib.dates as mdates
from matplotlib.ticker import AutoMinorLocator
dates = [datetime.datetime(2018, 1, 1) + datetime.timedelta(hours=k * 6)
for k in range(240)]
temperature = np.random.randn(len(dates)) * 4 + 6.7
fig, ax = plt.subplots(constrained_layout=True)
ax.plot(dates, temperature)
ax.set_ylabel(r'$T\ [^oC]$')
plt.xticks(rotation=70)
def date2yday(x):
"""Convert matplotlib datenum to days since 2018-01-01."""
y = x - mdates.date2num(datetime.datetime(2018, 1, 1))
return y
def yday2date(x):
"""Return a matplotlib datenum for *x* days after 2018-01-01."""
y = x + mdates.date2num(datetime.datetime(2018, 1, 1))
return y
secax_x = ax.secondary_xaxis('top', functions=(date2yday, yday2date))
secax_x.set_xlabel('yday [2018]')
def celsius_to_fahrenheit(x):
return x * 1.8 + 32
def fahrenheit_to_celsius(x):
return (x - 32) / 1.8
secax_y = ax.secondary_yaxis(
'right', functions=(celsius_to_fahrenheit, fahrenheit_to_celsius))
secax_y.set_ylabel(r'$T\ [^oF]$')
def celsius_to_anomaly(x):
return (x - np.mean(temperature))
def anomaly_to_celsius(x):
return (x + np.mean(temperature))
# use of a float for the position:
secax_y2 = ax.secondary_yaxis(
1.2, functions=(celsius_to_anomaly, anomaly_to_celsius))
secax_y2.set_ylabel(r'$T - \overline{T}\ [^oC]$')
plt.show()
Results in this:
I am trying to compute the intersection points between a line and a closed curve (stored in a file)
I tried to adapt this
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d
from scipy.optimize import bisect
import numpy as np
import csv
from scipy.interpolate import interp1d
from scipy.optimize import bisect
#reading curve from file
r = ...
z = ...
# vertical line
x = 1.885, 1.885
y = [-3,3]
z_ves = interp1d(r_ves, z_ves, fill_value="extrapolate")
plt.figure(num=None, figsize=(10, 6), dpi=100, facecolor='w', edgecolor='k')
plt.plot(r_ves, z_ves(r_ves))
plt.axvline(x=1.885,ymin=-3,ymax=3)
# #use interp1d to get interpolated points
y = interp1d(x, y, fill_value="extrapolate")
# stress = interp1d(strain, stress)
# #set starting points
x1 = max(x[0], r_ves[0])
x2 = min(x[-1], r_ves[-1])
max_err = .01
# #create function
f = lambda x : z_ves(x) - y(x)
#find x1 where f(x1) = 0
x1 = bisect(f, x1, x2, xtol = .001)
y1 = z_ves(x1)
#
plt.figure(num=None, figsize=(10, 6), dpi=100, facecolor='w', edgecolor='k')
plt.plot(r_ves, z_ves(r_ves))
plt.plot(x, y(x))
plt.scatter(x1, y1)
plt.show()
I get a Runtime Warning as I think the line is vertical.
RuntimeWarning: invalid value encountered in multiply
y_new = slope*(x_new - x_lo)[:, None] + y_lo
I know there are two intersections (see picture)
how do I get the intersections?
Function y should interpolate the vertical line, but you already know its equation: x=1.885. Therefore, plugging given x value into the equation of the curve should give you the equation you need to solve to get y-coordinates of the points of intersection. z_ves(1.885) should give you the desired result point of intersection.
I solved with using shapely
from shapely.geometry import LineString,Polygon
LOS1 = LineString([(1.885,-5), (1.885,3)])
VesselCoordTuple=list(zip(r_ves, z_ves))
polygonVesselBound = Polygon(VesselCoordTuple)
x1 = polygonVesselBound.intersection(LOS1)
r1 = x1.xy[0][0]
z1 = x1.xy[1][0]
r2 = x1.xy[0][1]
z2 = x1.xy[1][1]
plt.figure(1, figsize=SIZE, dpi=90) #1, figsize=(10, 4), dpi=180)
plt.plot(r_ves, z_ves)
plt.plot(x1.xy[0][0],x1.xy[1][0], color='r',linestyle=' ',marker='x',markersize=5)
plt.plot(x1.xy[0][1],x1.xy[1][1], color='r',linestyle=' ',marker='x',markersize=5)
i want to make graph using matplotlib in python.
np.load(name.npy')
i searched many things and i tried
for example..just...
x = [dt.datetime(2003, 05, 01), dt.datetime(2008, 06, 01)]
df = np.load(r'file')
y = df
Replace the end date on the date-range to your desired graph, and the 'y' should be array loaded
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
start_date = '2003-05-01'
y = np.load(r'c:\python27\abnormal.npy')
x = pd.date_range(start=start_date, periods=len(y), freq='D')
plt.plot(x,y,'.')
plt.show()
If your input array does not contain ordered pairs such as [(0,1), (1,1), (2,2)] and only contains one set of numbers '[1, 2, 3, 4]`, you neeed to create a set of x-coordinates. For a time series in days, you could try something like this:
import datetime
import numpy as np
import matplotlib.pyplot as plt
def getData(fileName):
# Load the data file to serve as y-axis coordinates
y = np.load(fileName)
# For each y coordinate we need an x coordinate
time_offset = list(range(len(y)))
# Convert time_offset to a time-series
# We will assume x-values equal number of days since a beginDate
x = []
beginDate = datetime.date(2015, 6, 1) # The date to begin our time series
for n in time_offset:
date = beginDate + datetime.timedelta(n) # Date + number_of_Days_passed
x.append(date)
return x, y
def plot(x, y):
# Plot the data
fig = plt.figure()
ax = plt.subplot2grid((1,1), (0,0), rowspan=1, colspan=1)
ax.scatter(x, y)
for label in ax.xaxis.get_ticklabels():
label.set_rotation(90)
ax.grid(True)
plt.subplots_adjust(left=.10, bottom=.19, right=.93, top=.95, wspace=.20, hspace=0)
plt.show()
x, y = getData('abnormal.npy')
plot(x, y)
The following formula is used to classify points from a 2-dimensional space:
f(x1,x2) = np.sign(x1^2+x2^2-.6)
All points are in space X = [-1,1] x [-1,1] with a uniform probability of picking each x.
Now I would like to visualize the circle that equals:
0 = x1^2+x2^2-.6
The values of x1 should be on the x-axis and values of x2 on the y-axis.
It must be possible but I have difficulty transforming the equation to a plot.
You can use a contour plot, as follows (based on the examples at http://matplotlib.org/examples/pylab_examples/contour_demo.html):
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-1.0, 1.0, 100)
y = np.linspace(-1.0, 1.0, 100)
X, Y = np.meshgrid(x,y)
F = X**2 + Y**2 - 0.6
plt.contour(X,Y,F,[0])
plt.show()
This yields the following graph
Lastly, some general statements:
x^2 does not mean what you think it does in python, you have to use x**2.
x1 and x2 are terribly misleading (to me), especially if you state that x2 has to be on the y-axis.
(Thanks to Dux) You can add plt.gca().set_aspect('equal') to make the figure actually look circular, by making the axis equal.
The solution of #BasJansen certainly gets you there, it's either very inefficient (if you use many grid points) or inaccurate (if you use only few grid points).
You can easily draw the circle directly. Given 0 = x1**2 + x**2 - 0.6 it follows that x2 = sqrt(0.6 - x1**2) (as Dux stated).
But what you really want to do is to transform your cartesian coordinates to polar ones.
x1 = r*cos(theta)
x2 = r*sin(theta)
if you use these substitions in the circle equation you will see that r=sqrt(0.6).
So now you can use that for your plot:
import numpy as np
import matplotlib.pyplot as plt
# theta goes from 0 to 2pi
theta = np.linspace(0, 2*np.pi, 100)
# the radius of the circle
r = np.sqrt(0.6)
# compute x1 and x2
x1 = r*np.cos(theta)
x2 = r*np.sin(theta)
# create the figure
fig, ax = plt.subplots(1)
ax.plot(x1, x2)
ax.set_aspect(1)
plt.show()
Result:
How about drawing x-values and calculating the corresponding y-values?
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-1, 1, 100, endpoint=True)
y = np.sqrt(-x**2. + 0.6)
plt.plot(x, y)
plt.plot(x, -y)
produces
This can obviously be made much nicer, but this is only for demonstration...
# x**2 + y**2 = r**2
r = 6
x = np.linspace(-r,r,1000)
y = np.sqrt(-x**2+r**2)
plt.plot(x, y,'b')
plt.plot(x,-y,'b')
plt.gca().set_aspect('equal')
plt.show()
produces:
Plotting a circle using complex numbers
The idea: multiplying a point by complex exponential () rotates the point on a circle
import numpy as np
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.pyplot as plt
num_pts=20 # number of points on the circle
ps = np.arange(num_pts+1)
# j = np.sqrt(-1)
pts = np.exp(2j*np.pi/num_pts *(ps))
fig, ax = plt.subplots(1)
ax.plot(pts.real, pts.imag , '-o')
ax.set_aspect(1)
plt.show()
I'm trying to interpolate my set of data (first columnt is the time, third columnt is the actual data):
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d
data = np.genfromtxt("data.csv", delimiter=" ")
x = data[:, 0]
y = data[:, 2]
xx = np.linspace(x.min(), x.max(), 1000)
y_smooth = interp1d(x, y)(xx)
#y_smooth = interp1d(x, y, kind="cubic")(xx)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(xx, y_smooth, "r-")
plt.show()
but I see some strange difference between linear and cubic interpolation.
Here is the result for linear:
Here is the same for cubic:
I'm not sure, why is graph jumping all the time and y_smooth contains incorrect values?
ipdb> y_smooth_linear.max()
141.5481144
ipdb> y_smooth_cubic.max()
1.2663431888584225e+18
Can anybody explain to me, how can I change my code to achieve correct interpolation?
UPD: here is data.cvs file
Your data contains several y values for the same x value. This violates the assumptions of most interpolation algorithms.
Either discard the rows with duplicate x values, average the y values for each individual x, or obtain a better resolution for the x values such that they aren't the same anymore.
Given cfh's observation that x has duplicate values, you could use np.unique
to select a unique value of y for each x:
x2, idx = np.unique(x, return_index=True)
y2 = y[idx]
return_index=True causes np.unique to return not only the unique values, x2, but also the locations, idx, of the unique xs in the original x array. Note that this selects the first value of y for each unique x.
If you'd like to average all the y values for each unique x, you could use
stats.binned_statistic:
import scipy.stats as stats
x2, inv = np.unique(x, return_inverse=True)
y2, bin_edges, binnumber = stats.binned_statistic(
x=inv, values=y, statistic='mean', bins=inv.max()+1)
return_inverse=True tells np.unique to return indices from which the
original array can be reconstructed. Those indices can also serve as categorical
labels or "factors", which is how they are being used in the call to
binned_statistic above.
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d
import scipy.stats as stats
data = np.genfromtxt("data.csv", delimiter=" ")
x = data[:, 0]
y = data[:, 1]
x2, idx, inv = np.unique(x, return_index=True, return_inverse=True)
y_uniq = y[idx]
y_ave, bin_edges, binnumber = stats.binned_statistic(
x=inv, values=y, statistic='mean', bins=inv.max()+1)
xx = np.linspace(x.min(), x.max(), 1000)
y_smooth = interp1d(x, y)(xx)
y_smooth2 = interp1d(x2, y_uniq, kind="cubic")(xx)
y_smooth3 = interp1d(x2, y_ave, kind="cubic")(xx)
fig, ax = plt.subplots(nrows=3, sharex=True)
ax[0].plot(xx, y_smooth, "r-", label='linear')
ax[1].plot(xx, y_smooth2, "b-", label='cubic (first y)')
ax[2].plot(xx, y_smooth3, "b-", label='cubic (ave y)')
ax[0].legend(loc='best')
ax[1].legend(loc='best')
ax[2].legend(loc='best')
plt.show()