Skip to content

twinx plot with datetime in xaxis fails in 3.1.3 #16405

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
icfly2 opened this issue Feb 4, 2020 · 9 comments
Closed

twinx plot with datetime in xaxis fails in 3.1.3 #16405

icfly2 opened this issue Feb 4, 2020 · 9 comments

Comments

@icfly2
Copy link

icfly2 commented Feb 4, 2020

Bug report

Bug summary

in 3.1.3 ax.twinx() with fails to plot the second plot if using datetime values for x axis.

Code for reproduction

import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import numpy as np

df = pd.DataFrame(index=pd.date_range(start='2020-01-26 22:00:00+00:00', end='2020-02-03 14:00:00+00:00', freq='H'),
                 data=np.random.rand(185, 5), columns = ['code_200','code_201','code_500','mean_200','mean_201'] )
fig, ax = plt.subplots( figsize=(15,6))
# plt.figure()
dfd = df.resample('D')[['code_200','code_201','code_500']].sum().tail(10)
# plt.bar(dfd)
plt.bar(dfd.index, dfd.code_200, color='#008c6e', label='sum of 200s')
plt.bar(dfd.index, dfd.code_201, bottom=dfd.code_200, color='k', label='sum of 201s')
plt.bar(dfd.index, dfd.code_500, bottom=dfd.code_200+dfd.code_201, color='#872d32',label='sum of 500s')

ax.yaxis.grid('both',color='k', linestyle='-', alpha=0.2)
ax.set_ylabel('# responses')
dfm = df.resample('D')[['mean_200', 'mean_201']].mean().tail(10)
ax2 = ax.twinx() 
ax2.plot(dfm.index, dfm.mean_200.values, label='avg for 200s', color='#808080')
ax2.plot(dfm.index, dfm.mean_201.values, label='avg for 201s', color='#872d32')
ax.legend(loc='upper left')
ax2.legend(loc='lower right')
ax2.set_ylabel('average response times [ms]')
ax.xaxis.set_major_formatter( mdates.DateFormatter('%a, %d-%b'))
plt.show()

Actual outcome

ax2.plot(dfm.index, dfm.mean_200.values, label='avg for 200s', color='#808080')
  File "/usr/local/lib/python3.7/site-packages/matplotlib/axes/_axes.py", line 1667, in plot
    self.add_line(line)
  File "/usr/local/lib/python3.7/site-packages/matplotlib/axes/_base.py", line 1902, in add_line
    self._update_line_limits(line)
  File "/usr/local/lib/python3.7/site-packages/matplotlib/axes/_base.py", line 1924, in _update_line_limits
    path = line.get_path()
  File "/usr/local/lib/python3.7/site-packages/matplotlib/lines.py", line 1027, in get_path
    self.recache()
  File "/usr/local/lib/python3.7/site-packages/matplotlib/lines.py", line 670, in recache
    x = _to_unmasked_float_array(xconv).ravel()
  File "/usr/local/lib/python3.7/site-packages/matplotlib/cbook/__init__.py", line 1390, in _to_unmasked_float_array
    return np.asarray(x, float)
  File "/usr/local/lib/python3.7/site-packages/numpy/core/_asarray.py", line 85, in asarray
    return array(a, dtype, copy=False, order=order)
TypeError: float() argument must be a string or a number, not 'Timestamp'

Expected outcome

image

The image was generated with matplotlib version 3.1.0 it fails in 3.1.3

Matplotlib version

  • Operating system: Works with 3.1.0 on Windows 10 and Linux (python docker)
  • Matplotlib version: 3.1.0 / 3.1.3
  • Matplotlib backend (print(matplotlib.get_backend())): agg
  • Python version: 3.7
  • Jupyter version (if applicable): nope
  • Other libraries: pandas = 1.0.0 and 0.24.1 both work / fail

All installed from pip.

@anntzer
Copy link
Contributor

anntzer commented Feb 4, 2020

On 3.1.x this bisects to #16382, but this is not present in master even though the same commit is there.

@timhoffm
Copy link
Member

timhoffm commented Feb 4, 2020

Works for me both on 3.1.x and master (tested with pandas 0.24.1 and numpy 1.16.2). Maybe the numpy version is relevant as well?

@jklymak
Copy link
Member

jklymak commented Feb 5, 2020

works numpy = 1.17.5, panda = 1.0.0

@icfly2
Copy link
Author

icfly2 commented Feb 5, 2020

I'll recreate the docker container with the failing plot later and report back the full requirements / dependencies. The change in matplotlib version was what fixed it though.

@icfly2
Copy link
Author

icfly2 commented Feb 5, 2020

Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/web/dashboard/asap_utils.py", line 107, in make_SWUBS_plots
    ax2.plot(dfm.index, dfm.mean_200.values, label='avg for 200s', color='#808080', linewidth=4)
  File "/usr/local/lib/python3.7/site-packages/matplotlib/axes/_axes.py", line 1667, in plot
    self.add_line(line)
  File "/usr/local/lib/python3.7/site-packages/matplotlib/axes/_base.py", line 1902, in add_line
    self._update_line_limits(line)
  File "/usr/local/lib/python3.7/site-packages/matplotlib/axes/_base.py", line 1924, in _update_line_limits
    path = line.get_path()
  File "/usr/local/lib/python3.7/site-packages/matplotlib/lines.py", line 1027, in get_path
    self.recache()
  File "/usr/local/lib/python3.7/site-packages/matplotlib/lines.py", line 670, in recache
    x = _to_unmasked_float_array(xconv).ravel()
  File "/usr/local/lib/python3.7/site-packages/matplotlib/cbook/__init__.py", line 1390, in _to_unmasked_float_array
    return np.asarray(x, float)
  File "/usr/local/lib/python3.7/site-packages/numpy/core/_asarray.py", line 85, in asarray
    return array(a, dtype, copy=False, order=order)
TypeError: float() argument must be a string or a number, not 'Timestamp'
>>> import matplotlib
>>> matplotlib.__version__
'3.1.3'
>>> import pandas as pd
>>> pd.__version__
'1.0.0'
>>> import numpy as np
>>> np.__version__
'1.18.1'

The code:

from datetime import timedelta
from django_rq import get_scheduler
import sxptools
import pandas as pd
from django.db.models import Max
from .models import ASAPperformance
import datetime
from pytz import UTC
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import numpy as np
import pandas as pd

def make_plots():
    df = pd.DataFrame(index=pd.date_range(start='2020-01-26 22:00:00+00:00', end='2020-02-03 14:00:00+00:00', freq='H'),
                 data=np.random.rand(185, 5), columns = ['code_200','code_201','code_500','mean_200','mean_201'] )
    fig, ax = plt.subplots( figsize=(15,6))
    dfd = df.resample('D')[['code_200','code_201','code_500']].sum().tail(10)
    plt.bar(dfd.index, dfd.code_200, color='#008c6e', label='sum of 200s')
    plt.bar(dfd.index, dfd.code_201, bottom=dfd.code_200, color='k', label='sum of 201s')
    plt.bar(dfd.index, dfd.code_500, bottom=dfd.code_200+dfd.code_201, color='#872d32',label='sum of 500s')

    ax.yaxis.grid('both',color='k', linestyle='-', alpha=0.2)
    ax.set_ylabel('# responses')
    ax.legend(loc='upper left')



    dfm = df.resample('D')[['mean_200', 'mean_201']].mean().tail(10)
    ax2 = ax.twinx() 
    ax2.plot(dfm.index, dfm.mean_200.values, label='avg for 200s', color='#808080', linewidth=4)
    ax2.plot(dfm.index, dfm.mean_201.values, label='avg for 201s', color='k', linewidth=4)

    ax2.legend(loc='lower left')
    ax2.set_ylabel('average response times [ms]')
    ax.xaxis.set_major_formatter( mdates.DateFormatter('%a, %d-%b'))
    ax.xaxis.set_tick_params(rotation=45)
    # i = 0
    # for val in  ['8.20%', '33.52%', '35.35%', '37.21%', '34.14%', '36.12%', '33.40%', '35.45%', '36.90%']:
    #     ax.text(dfd.index[i], dfd.code_200.mean(), val, horizontalalignment='center',color='w', fontsize=22)
    #     i +=1
    fig.savefig('dashboard/static/images/sum_plot.png', bbox_inches='tight', transparent=True)

Works with:

>>> import matplotlib
>>> matplotlib.__version__
'3.1.0'
>>> import numpy as np; np.__version__
'1.18.1'
>>> import pandas as pd; pd.__version__
'1.0.0'
>>> import django
>>> django.__version__
'2.2.10'

Both on a python:37 docker container running on RHEL server, through django shell

@icfly2
Copy link
Author

icfly2 commented Feb 5, 2020

Django>=2.0,<3.0
psycopg2>=2.7,<3.0
matplotlib==3.1.0 # this works 3.1.3 and it fails # 3.1.2 and it works
pandas==1.0
numpy==1.18.1

@jklymak
Copy link
Member

jklymak commented Feb 5, 2020

numpy=1.18.1, pandas=1.0, v3.1.x on master and this works fine. I would guess you have an install crossed somewhere.

@jklymak
Copy link
Member

jklymak commented Feb 11, 2020

I'm going to close this because we can't reproduce, but feel free to follow up if its still a problem.

@jklymak jklymak closed this as completed Feb 11, 2020
@adfernandes
Copy link

adfernandes commented Mar 25, 2020

Same error on macOS, using Conda with numpy == 1.18.1, matplotlib == 3.1.3, and pandas == 1.0.2.

I have a DateTimeIndex x-axis, and get the error

 [...]
 File "/opt/conda/envs/covid19/lib/python3.8/site-packages/matplotlib/text.py", line 1759, in _get_xy
    x = float(self.convert_xunits(x))
TypeError: float() argument must be a string or a number, not 'Timestamp'

And it is a clean environment, exported and re-imported, with no version conflicts (and all packages up-to-date).

The sample code at the top of this PR fails for me, also, with the same error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants