I would like to generate sequence of ordered numbers which is of same length of some other list. I have tried
def parse_data_from_file(filename):
times = []
temperatures = []
with open(filename) as csvfile:
reader = csv.reader(csvfile, delimiter=',')
next(reader)
for row in reader:
times.append(row[0])
temperatures.append(float(row[1]))
return times, temperatures
The issue is time is not getting represnted properly on x-axis as attached here:
You haven't said how you're making the plots. I'll assume you're using matplotlib, which is probably the most popular plotting package for Python.
I know that when I'm working with dates or times, I usually use datetime.strptime() to get the data into a datetime format that Python likes:
from datetime import datetime
# assume your date info looks like 08-Jun-2022 14:22:22
dt = datetime.strptime(row[0], '%d-%b-%Y %H:%M:%S')
times.append(dt)
Matplotlib has a convenience function date2num that converts a datetime object to a format that it likes to use. Their official example is here. Here is an even shorter example for you:
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import matplotlib
fig, ax = plt.subplots()
t = matplotlib.dates.date2num(times)
y = temperatures
ax.plot(t, y)
ax.xaxis.set_major_locator(mdates.MonthLocator(bymonth=(1, 7)))
Related
i want to add a string Comment above every single candle using mplfinance package .
is there a way to do it using mplfinance or any other package ?
here is the code i used :
import pandas as pd
import mplfinance as mpf
import matplotlib.animation as animation
from mplfinance import *
import datetime
from datetime import date, datetime
fig = mpf.figure(style="charles",figsize=(7,8))
ax1 = fig.add_subplot(1,1,1 , title='ETH')
def animate(ival):
idf = pd.read_csv("test1.csv", index_col=0)
idf['minute'] = pd.to_datetime(idf['minute'], format="%m/%d/%Y %H:%M")
idf.set_index('minute', inplace=True)
ax1.clear()
mpf.plot(idf, ax=ax1, type='candle', ylabel='Price US$')
ani = animation.FuncAnimation(fig, animate, interval=250)
mpf.show()
You should be able to do this using Axes.text()
After calling mpf.plot() then call
ax1.text()
for each text that you want (in your case for each candle).
There is an important caveat regarding the x-axis values that you pass into ax1.text():
If you do not specify show_nontrading=True then it will default to False in which case the x-axis value that you pass into ax1.text() for the position of the text must be the row number corresponding to the candle where you want the text counting from 0 for the first row in your DataFrame.
On the other hand if you do set show_nontrading=True then the x-axis value that you pass into ax1.text() will need to be the matplotlib datetime. You can convert pandas datetimes from you DataFrame DatetimeIndex into matplotlib datetimes as follows:
import matplotlib.dates as mdates
my_mpldates = mdates.date2num(idf.index.to_pydatetime())
I suggest using the first option (DataFrame row number) because it is simpler. I am currently working on an mplfinance enhancement that will allow you to enter the x-axis values as any type of datetime object (which is the more intuitive way to do it) however it may be another month or two until that enhancement is complete, as it is not trivial.
Code example, using data from the mplfinance repository examples data folder:
import pandas as pd
import mplfinance as mpf
infile = 'data/yahoofinance-SPY-20200901-20210113.csv'
# take rows [18:28] to keep the demo small:
df = pd.read_csv(infile, index_col=0, parse_dates=True).iloc[18:25]
fig, axlist = mpf.plot(df,type='candle',volume=True,
ylim=(330,345),returnfig=True)
x = 1
y = df.loc[df.index[x],'High']+1
axlist[0].text(x,y,'Custom\nText\nHere')
x = 3
y = df.loc[df.index[x],'High']+1
axlist[0].text(x,y,'High here\n= '+str(y-1),fontstyle='italic')
x = 5
y = df.loc[df.index[x],'High']+1
axlist[0].text(x-0.2,y,'More\nCustom\nText\nHere',fontweight='bold')
mpf.show()
Comments on the above code example:
I am setting the ylim=(330,345) in order to provide a little extra room above the candles for the text. In practice you might choose the high dynamically as perhaps high_ylim = 1.03*max(df['High'].values).
Notice that the for first two candles with text, the text begins at the center of the candle. The 3rd text call uses x-0.2 to position the text more over the center of the candle.
For this example, the y location of the candle is determined by taking the high of that candle and adding 1. (y = df.loc[df.index[x],'High']+1) Of course adding 1 is arbitrary, and in practice, depending on the maginitude of your prices, adding 1 may be too little or too much. Rather you may want to add a small percentage, for example 0.2 percent:
y = df.loc[df.index[x],'High']
y = y * 1.002
Here is the plot the above code generates:
I have two lists representing dates and values respectively:
dates = ['10/6/2020',
'10/7/2020',
'10/8/2020',
'10/9/2020',
'10/12/2020',
'10/13/2020',
'10/14/2020',
'10/15/2020',
'10/16/2020',
'10/19/2020']
and
values = ['40.660',
'39.650',
'41.010',
'41.380',
'39.950',
'40.790',
'41.050',
'40.370',
'40.880',
'40.860']
I want to use seaborn/matplotlib to plot them without using pandas. Is that possible? I've made a few attempts but it doesn't seem to be going too well.
Here's what I've got so far:
def plots(values=values,dates=dates):
sns.lineplot(x=dates,y=sorted(values)[::-1])
sns.scatterplot(x=dates,y=sorted(values)[::-1])
plt.show()
return
crude_data = plots()
But it gives me this:
This is obviously wrong but I don't know how to fix it. The x-axis is also messy, and I'd like to fix that as well and make it more legible without expanding the width of the graph if possible. If that's impossible, then a way to do so while expanding the graph would be happily accepted as well.
Cheers!
Just parse dates from string to datetime.
Otherwise they are treated as strings and lose all their properties besides sortability (which can be wrong, depending on date format).
Also add xticks rotation for better x axis labels.
edit:
Also as others noticed, your numeric data is in string type aswell.
import seaborn as sns
import matplotlib.pyplot as plt
import datetime
dates = ['10/6/2020',
'10/7/2020',
'10/8/2020',
'10/9/2020',
'10/12/2020',
'10/13/2020',
'10/14/2020',
'10/15/2020',
'10/16/2020',
'10/19/2020']
values = ['40.660',
'39.650',
'41.010',
'41.380',
'39.950',
'40.790',
'41.050',
'40.370',
'40.880',
'40.860']
dates = [datetime.datetime.strptime(date, '%m/%d/%Y') for date in dates]
values = [float(val) for val in values]
def plots(values=values,dates=dates):
sns.lineplot(x=dates,y=sorted(values)[::-1])
sns.scatterplot(x=dates,y=sorted(values)[::-1])
plt.xticks(rotation=45)
plt.show()
return crude_data = plots()
You can use datetime library.
import matplotlib.pyplot as plt
from datetime import datetime
import seaborn as sns
dates = ['10/6/2020',
'10/7/2020',
'10/8/2020',
'10/9/2020',
'10/12/2020',
'10/13/2020',
'10/14/2020',
'10/15/2020',
'10/16/2020',
'10/19/2020']
x = [datetime.strptime(i, '%m/%d/%Y') for i in dates]
values = ['40.660',
'39.650',
'41.010',
'41.380',
'39.950',
'40.790',
'41.050',
'40.370',
'40.880',
'40.860']
nvalues = [float(i) for i in values]
def plots(values=nvalues,dates=x):
sns.lineplot(x=dates,y=sorted(values)[::-1])
sns.scatterplot(x=dates,y=sorted(values)[::-1])
plt.xticks(rotation=45, ha='right')
plt.show()
return
import matplotlib.pyplot as plt
from datetime import datetime
crude_data = plots()
Output:
I made 3 changes to your code:
I set the y axis data to be float instead of string by removing the '',
I removed sorted from the two plot lines, and
I added sort=False to the lineplot call
import matplotlib.pyplot as plt
import seaborn as sns
dates = ['10/6/2020',
'10/7/2020',
'10/8/2020',
'10/9/2020',
'10/12/2020',
'10/13/2020',
'10/14/2020',
'10/15/2020',
'10/16/2020',
'10/19/2020']
values = [40.660,
39.650,
41.010,
41.380,
39.950,
40.790,
41.050,
40.370,
40.880,
40.860]
def plots(values=values,dates=dates):
sns.lineplot(x=dates,y=values[::-1], sort=False)
s = sns.scatterplot(x=dates,y=values[::-1])
plt.xticks(rotation=45, ha='right')
plt.show()
return s
crude_data = plots()
This gives:
I need to display the time in the x axis using matplotlib, not panda. The y axis should display the temperature. The data has been generated from an api and extracted, before being placed into a multidimensional list. My latest attempt is below. the time is not displayed accurately.
import matplotlib.pyplot as plt
import numpy as np
import urllib.request
import json
from datetime import datetime, timedelta, time
import matplotlib
def graph_data():
weather_api = 'http://api.openweathermap.org/data/2.5/forecast?q=London&id='
source_code = urllib.request.urlopen(weather_api)
content = source_code.read()
codes = json.loads(content.decode("utf8"))
#get the data required and put it in an array called 'weather_data'
weather_data=[]
for each in codes['list']:
weather_data.append([
each['dt_txt'],
each['weather'][0]['description'],
int(each['main']['humidity']),
float(each['wind']['speed']),
int(each['main']['temp_min']),
int(each['main']['temp_max'])])
#store the weather details for each day
day1 = datetime.now()+timedelta(days=1)
forecast_list = []
for each in weather_data:
date=datetime.strptime(each[0], '%Y-%m-%d %H:%M:%S') #convert string to date
if day1.day == date.day:
d=datetime.strptime(each[0],'%Y-%m-%d %H:%M:%S')
# time=d.strftime('%H:%M:%S')
forecast_list.append([d, each[4]])
time=[]
temp=[]
for each in forecast_list:
time.append(each[0])
temp.append(each[1])
print(time)
plt.plot(time, temp, label = 'Temperature')
plt.gcf().autofmt_xdate()
plt.xlabel('Time')
plt.ylabel('Temperature')
plt.title('Temperature for {0}'.format(day1.strftime('%Y-%d-%d')))
plt.legend()
plt.show()
graph_data()
You say "displays part of the year and a random number"—probably it is displaying the time accurately, but as a fractional year. What format do you want it to use?
Try using plt.plot_date instead of plt.plot.
Or, after plotting, you can do
ax = plt.gca()
ax.xaxis_date() # treat the x-axis as dates
ax.xaxis.set_major_formatter(matplotlib.dates.DateFormatter('%H:%M')) # specify the format you want
I have the following code to plot a chart with matplotlib
#!/usr/bin/env python
import matplotlib.pyplot as plt
import urllib2
import json
req = urllib2.urlopen("http://localhost:17668/retrieval/data/getData.json? pv=LNLS:ANEL:corrente&donotchunk")
data = json.load(req)
secs = [x['secs'] for x in data[0]['data']]
vals = [x['val'] for x in data[0]['data']]
plt.plot(secs, vals)
plt.show()
The secs arrays is epoch time.
What I want is to plot the data in the x axis (secs) as a date (DD-MM-YYYY HH:MM:SS).
How can I do that?
To plot date-based data in matplotlib you must convert the data to the correct format.
One way is to first convert your data to datetime objects, for an epoch timestamp you should use datetime.datetime.fromtimestamp().
You must then convert the datetime objects to the right format for matplotlib, this can be handled using matplotlib.date.date2num.
Alternatively you can use matplotlib.dates.epoch2num and skip converting your date to datetime objects in the first place (while this will suit your use-case better initially, I would recommend trying to keep date based date in datetime objects as much as you can when working, it will save you a headache in the long run).
Once you have your data in the correct format you can plot it using plot_date.
Finally to format your x-axis as you wish you can use a matplotlib.dates.DateFormatter object to choose how your ticks will look.
import matplotlib.pyplot as plt
import matplotlib.dates as mdate
import numpy as np
# Generate some random data.
N = 40
now = 1398432160
raw = np.array([now + i*1000 for i in range(N)])
vals = np.sin(np.linspace(0,10,N))
# Convert to the correct format for matplotlib.
# mdate.epoch2num converts epoch timestamps to the right format for matplotlib
secs = mdate.epoch2num(raw)
fig, ax = plt.subplots()
# Plot the date using plot_date rather than plot
ax.plot_date(secs, vals)
# Choose your xtick format string
date_fmt = '%d-%m-%y %H:%M:%S'
# Use a DateFormatter to set the data to the correct format.
date_formatter = mdate.DateFormatter(date_fmt)
ax.xaxis.set_major_formatter(date_formatter)
# Sets the tick labels diagonal so they fit easier.
fig.autofmt_xdate()
plt.show()
You can change the ticks locations and formats on your plot:
import matplotlib.pyplot as plt
import matplotlib.ticker as mtick
import time
secs = [10928389,102928123,383827312,1238248395]
vals = [12,8,4,12]
plt.plot(secs,vals)
plt.gcf().autofmt_xdate()
plt.gca().xaxis.set_major_locator(mtick.FixedLocator(secs))
plt.gca().xaxis.set_major_formatter(
mtick.FuncFormatter(lambda pos,_: time.strftime("%d-%m-%Y %H:%M:%S",time.localtime(pos)))
)
plt.tight_layout()
plt.show()
I am trying to plot a graph after having imported data from a CSV file and stored it as two separate lists. Is it possible for matplotlib to plot a graph using a list of strings, or is it necessary for the lists two be lists of "int" ?
If not, why is the following code not working?
Error prompted:
invalid literal for int() with base 10: '02_13_2014'
My code:
import csv
import numpy as np
from numpy import genfromtxt
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
with open('pytdef.csv','r') as f:
reader = csv.reader(f)
for row in reader:
print (row)
first_column= ['Date']
second_column = ['Value']
Date_list = []
Value_list = []
with open('pytdef.csv') as f:
reader = csv.reader(f)
for row in reader:
Date_list.append(row[0])
with open('pytdef.csv') as f:
reader = csv.reader(f)
for row in reader:
Value_list.append(row[1])
print (Date_list)
print (Value_list)
Date_list = list(map(int,Date_list))
print (Date_list)
print (Value_list)
fig = plt.figure()
plt.plot_date(x=Date_list, y=Value_list)
plt.show()
I think the problem here is your date. The code here is a lot simpler if you just use pandas
#!/usr/bin/env python
%matplotlib inline
import pandas as pd
import matplotlib.pyplot as plt
from datetime import date
columns = ['dates', 'value']
data = pd.read_csv('/location_of_file/file_name.csv', header=False, names=columns)
I'm assuming your data looks something like this...
then format the date
data['dates'] = [date(int(x.split('_')[2]), int(x.split('_')[0]),
int(x.split('_')[1])) for x in data.dates]
plt.plot(data.dates, data.value);