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:
Related
In the timeline plot I’m making, I want date tickers to show only specified dates. (In my example I show tickers for events ‘A’, but it can be any list on tickers). I found how to do it when x-axis data is numeric (upper subplot in my example), but this won’t work with timestamp date type (bottom plot).
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import matplotlib.ticker as ticker
myData = pd.DataFrame({'date':['2019-01-15','2019-02-10','2019-03-20','2019-04-17','2019-05-23','2019-06-11'],'cnt':range(6),'event':['a','b','a','b','a','b']})
myData['date'] = [pd.Timestamp(j) for j in myData['date']]
start = pd.Timestamp('2019-01-01')
stop = pd.Timestamp('2019-07-01')
inxa = myData.loc[myData['event'] == 'a'].index
inxb = myData.loc[myData['event'] == 'b'].index
# create two plots, one with 'cnt' as x-axis, the other 'dates' on x-axis.
fig, ax = plt.subplots(2,1,figsize=(16,9))
ax[0].plot((0,6),(0,0), 'k')
ax[1].plot((start, stop),(0,0))
for g in inxa:
ax[0].plot((myData.loc[g,'cnt'],myData.loc[g,'cnt']),(0,1),c='r')
ax[1].plot((myData.loc[g,'date'],myData.loc[g,'date']),(0,1),c='r')
for g in inxb:
ax[0].plot((myData.loc[g,'cnt'],myData.loc[g,'cnt']),(0,2),c='b')
ax[1].plot((myData.loc[g,'date'],myData.loc[g,'date']),(0,2),c='b')
xlist0 = myData.loc[myData['event']=='a','cnt']
xlist1 = myData.loc[myData['event']=='a','date']
ax[0].xaxis.set_major_locator(ticker.FixedLocator(xlist0))
# ax[1].xaxis.set_major_locator(**???**)
Couldn't find a sufficient duplicate, maybe I didn't look hard enough. There are a number of ways to do this:
Converting to numbers first or using the underlying values of a Pandas DateTime Series
xticks = [mdates.date2num(z) for z in xlist1]
# or
xticks = xlist1.values
and at least a couple ways to use it/them
ax[1].xaxis.set_major_locator(ticker.FixedLocator(xticks))
ax[1].xaxis.set_ticks(xticks)
Date tick labels
How to set the xticklabels for date in matplotlib
how to get ticks every hour?
...
I haven't used matplotlib in years, but now for a project, I wanted to use it. I have lists of dates and decimal values inside a list. There are ~300 records, so here's a small snippet of that:
[['2015-01-08', '174.0'], ['2015-01-09', '172.0'], ['2015-01-11', '170.5']]
As you can tell, there are some gaps in the data, which sometimes last weeks. I want to plot all these values in a graph, with the time and decimal values. I don't know what to do. All help is appreciated. If it helps, here is an example of what I want it to look like (Without all the styling, of course):
Also, here is all the data, if needed: https://pastebin.com/esEPp78j
Thanks a lot!
With pure matplotlib:
from datetime import datetime
import matplotlib.pyplot as plt
a = [['2015-01-08', '174.0'], ['2015-01-09', '172.0'], ['2015-01-11', '170.5']]
dates = [datetime.strptime(d[0], "%Y-%m-%d") for d in a]
values = [float(d[1]) for d in a]
plt.plot(dates, values)
plt.show()
With numpy:
import numpy as np
import matplotlib.pyplot as plt
a = [['2015-01-08', '174.0'], ['2015-01-09', '172.0'], ['2015-01-11', '170.5']]
dates, values = np.array(a).T
dates = dates.astype(np.datetime64)
values = values.astype(float)
plt.plot(dates, values)
plt.show()
With pandas
import pandas as pd
import matplotlib.pyplot as plt
a = [['2015-01-08', '174.0'], ['2015-01-09', '172.0'], ['2015-01-11', '170.5']]
df = pd.DataFrame(a, columns=["dates", "values"])
df["dates"] = pd.to_datetime(df["dates"])
df["values"] = pd.to_numeric(df["values"])
plt.plot("dates", "values", data=df)
plt.show()
I have a dataFrame with datetimeIndex and two columns with int values. I would like to plot on the same graph Col1 as a bar plot, and Col2 as a line plot.
Important feature is to have correctly labeled x-axis as datetime, also when zooming in-out. I think solutions with DateFormatter would not work, since I want a dynamic xtick labeling.
import matplotlib.pyplot as plt
import pandas as pd
import datetime as dt
import numpy as np
startDate = dt.datetime(2018,1,1,0,0)
nrHours = 144
datetimeIndex = [startDate + dt.timedelta(hours=x) for x in range(0,nrHours)]
dF = pd.DataFrame(index=datetimeIndex)
dF['Col1'] = np.random.randint(1,3,nrHours)
dF['Col2'] = np.random.randint(3,6,nrHours)
axes = dF[['Col1']].plot(kind='bar')
dF[['Col2']].plot(ax=axes)
What seemed to be a simple task turns out being very challenging. Actually, after extensive search on the net, I still haven't found any clean solutions.
I have tried to use both pandas plot and matplotlib.
The main issue arises from the bar plot that seems to have difficulties handling datetime index (prefers integers, in some cases it plot dates but in Epoch 1970-1-1 style which is equivalent to 0).
I finally found a way using mdates and date2num. The solution is not very clean but provides an efficient solution to:
Combine bar and line plot on same graph
Using datetime on x-axis
Correctly and dynamically displaying x-ticks time labels (also when zooming in and out)
Working example :
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import pandas as pd
import datetime as dt
import numpy as np
startDate = dt.datetime(2018,1,1,0,0)
nrHours = 144
datetimeIndex = [startDate + dt.timedelta(hours=x) for x in range(0, nrHours)]
dF = pd.DataFrame(index=datetimeIndex)
dF['Col1'] = np.random.randint(1,3,nrHours)
dF['Col2'] = np.random.randint(3,6,nrHours)
fig,axes = plt.subplots()
axes.xaxis_date()
axes.plot(mdates.date2num(list(dF.index)),dF['Col2'])
axes.bar(mdates.date2num(list(dF.index)),dF['Col1'],align='center',width=0.02)
fig.autofmt_xdate()
Sample output:
I am plotting such data:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import pandas as pd
a = pd.DatetimeIndex(start='2010-01-01',end='2011-06-01' , freq='M')
b = pd.Series(np.random.randn(len(a)), index=a)
I would like the plot to be in the format of bars, so I use this:
b.plot(kind='bar')
This is what I get:
As you can see, the dates are formatted in full, which is very ugly and unreadable. I happened to test this command which creates a very nice Date format:
b.plot()
As you can see:
I like this format very much, it includes the months, marks the beginning of the year and is easily readable.
After doing some search, the closest I could get to that format is using this:
fig, ax = plt.subplots()
ax.plot(b.index, b)
ax.xaxis.set_major_formatter(mdates.DateFormatter('%b'))
However the output looks like this:
I am able to have month names on x axis this way, but I like the first formatting much more. That is much more elegant. Does anyone know how I can get the same exact xticks for my bar plot?
Here's a solution that will get you the format you're looking for. You can edit the tick labels directly, and use set_major_formatter() method:
fig, ax = plt.subplots()
ax.bar(b.index, b)
ticklabels = [item.strftime('%b') for item in b.index] #['']*len(b.index)
ticklabels[::12] = [item.strftime('%b\n%Y') for item in b.index[::12]]
ax.xaxis.set_major_formatter(matplotlib.ticker.FixedFormatter(ticklabels))
ax.set_xticks(b.index)
plt.gcf().autofmt_xdate()
Output:
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()