1

Good day,

I am trying to plot two arrays (timesin and locations) as a scatter of points. However, because timesin is a datetime object (of which I want time only), I find that I can only plot it properly using pyplot.plot(), not pyplot.scatter(). The issue arrises when I want to color the points on this plot with a third variable, idx. I know pyplot.scatter() is capable of doing this quite easily, but I don't know how to do it with pyplot.plot().

My excerpt of code:

import os
import tempfile
from datetime import datetime
import numpy as np
os.environ['MPLCONFIGDIR'] = tempfile.mkdtemp()

import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages

pp = PdfPages('output.pdf')
names = ['WestHall', 'Elevator', 'EastHall', 'MathLounge']
locations = np.arange(4)+1
plt.scatter(timesin, locations, c=idx, marker="o")
plt.xlabel("Time of day")
plt.ylabel("Location")
plt.yticks(np.arange(4)+1, names)
plt.gcf().autofmt_xdate()
pp.savefig()
plt.close()
pp.close()

When I try this, I get an error, because it tries to interpret idx as rgba:

ValueError: to_rgba: Invalid rgba arg "[...]"
number in rbg sequence outside 0-1 range

How do I get it to interpret idx as conditional coloring without using pyplot.scatter()?

Thanks

Update:

As suggested by Hun, I actually can use pyplot.scatter() in this context by converting the datetime objects to numbers using matplotlibs dates library. Thus, figuring out how to use pyplot.plot() for conditional coloring was unnecessary.

Community
  • 1
  • 1
Nathan Goedeke
  • 115
  • 1
  • 8
  • You marked Hun's answer as the answer, but this doesn't answer your question. You should change your question to claim that Hun have answered it. – Alejandro Apr 10 '16 at 20:34

2 Answers2

2

It would be easier if you use plt.scatter(). But you need to convert the datetime to something scatter() can understand. There is a way to do it.

>>> dt # datetime numpy array
array(['2005-02-01', '2005-02-02', '2005-02-03', '2005-02-04'], dtype='datetime64[D]')

>>> dt.tolist() # need to be converted to list
[datetime.date(2005, 2, 1), datetime.date(2005, 2, 2), datetime.date(2005, 2, 3), datetime.date(2005, 2, 4)]

# convert the list to internal time information for matplotlib. But this is float.
>>> dt1 = matplotlib.dates.date2num(dt.tolist())
array([ 731978.,  731979.,  731980.,  731981.])

With this dt1 you can use plt.scatter()

Hun
  • 3,707
  • 2
  • 15
  • 15
0

I think that it is not possible to do this at once with matplotlib.pyplot.plot. However, here is my solution:

import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm

def scatterplot(x,y,prop):
    prop = cm.jet((prop-np.min(prop))/(np.max(prop)-np.min(prop)))
    ax = plt.gca()
    for i in xrange(len(x)):
        ax.plot(x[i],y[i],color=prop[i], marker='o')
    return

x = np.random.rand(100)
y = np.random.rand(100)
prop = -20+40*np.random.rand(100)

fig = plt.figure(1,figsize=(5,5))
ax  = fig.add_subplot(111)
scatterplot(x,y,prop)
plt.show()

which produces:

enter image description here

The only drawback of this approach is that if you have several particles, the process of walk through all of them can be relatively slow.

EDIT (In response to @Nathan Goedeke's comment:

I tried the same implementation but using a datetime object:

import numpy as np
import matplotlib.pyplot as plt
import datetime as dt

x = np.array([dt.datetime(2016, 10, 19, 10, 0, 0),
              dt.datetime(2016, 10, 19, 10, 0, 1),
              dt.datetime(2016, 10, 19, 10, 0, 2),
              dt.datetime(2016, 10, 19, 10, 0, 3)])

fig = plt.figure()
y = np.array([1, 3, 4, 2])
prop = np.array([2.,5.,3.,1.])
scatterplot(x,y,prop)
plt.show()

and it works as well.

Alejandro
  • 3,263
  • 2
  • 22
  • 38
  • Because my data to plot are datetime objects, I get an error when I try to implement this: `ValueError: ordinal must be >= 1` – Nathan Goedeke Apr 10 '16 at 19:43
  • Could you please write a minimum working example? I can not test it with your example... – Alejandro Apr 10 '16 at 19:47
  • You said that pyplot.plot worked for you, so I don't see why now you complain about this implementation, which actually uses pyplot.plot. – Alejandro Apr 10 '16 at 19:49
  • My example is the same as the code in my question only with the addition of `timesin` being an array of datetime objects. – Nathan Goedeke Apr 10 '16 at 19:53
  • I know pyplot.plot works, but for some reason when I tried your implementation I got a long traceback ending with `File "/usr/lib/pymodules/python2.7/matplotlib/dates.py", line 203, in _from_ordinalf dt = datetime.datetime.fromordinal(ix) ValueError: ordinal must be >= 1` – Nathan Goedeke Apr 10 '16 at 19:55
  • I have tested it with datetime objects and edited my answer. It works as well, so your error seems to depend on your particular implementation within dates.py rather than a problem with my solution. – Alejandro Apr 10 '16 at 20:26
  • Thanks, but I found it was easier to convert to numbers and use Hun's suggestion – Nathan Goedeke Apr 10 '16 at 20:30