Json serialization error using matplotlib mpld3 with LinkedBrush - python

The mpld3 (matplotlib on d3) example for LinkedBrush
http://mpld3.github.io/examples/linked_brush.html provides the following code example:
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
import mpld3
from mpld3 import plugins, utils
data = load_iris()
X = data.data
y = data.target
# dither the data for clearer plotting
X += 0.1 * np.random.random(X.shape)
fig, ax = plt.subplots(4, 4, sharex="col", sharey="row", figsize=(8, 8))
fig.subplots_adjust(left=0.05, right=0.95, bottom=0.05, top=0.95,
hspace=0.1, wspace=0.1)
for i in range(4):
for j in range(4):
points = ax[3 - i, j].scatter(X[:, j], X[:, i],
c=y, s=40, alpha=0.6)
# remove tick labels
for axi in ax.flat:
for axis in [axi.xaxis, axi.yaxis]:
axis.set_major_formatter(plt.NullFormatter())
# Here we connect the linked brush plugin
plugins.connect(fig, plugins.LinkedBrush(points))
mpld3.show()
While the public web page shows the matrix of linked outputs, when running it locally there is a json serialization error:
Traceback (most recent call last):
File "/git/scalatesting/src/main/python/mpld3_linkedbrush.py", line 34, in <module>
mpld3.show()
File "/usr/local/lib/python2.7/site-packages/mpld3/_display.py", line 358, in show
html = fig_to_html(fig, **kwargs)
File "/usr/local/lib/python2.7/site-packages/mpld3/_display.py", line 251, in fig_to_html
figure_json=json.dumps(figure_json, cls=NumpyEncoder),
File "/usr/local/Cellar/python/2.7.14/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py", line 251, in dumps
sort_keys=sort_keys, **kw).encode(obj)
File "/usr/local/Cellar/python/2.7.14/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 207, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/local/Cellar/python/2.7.14/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 270, in iterencode
return _iterencode(o, 0)
File "/usr/local/lib/python2.7/site-packages/mpld3/_display.py", line 138, in default
return json.JSONEncoder.default(self, obj)
File "/usr/local/Cellar/python/2.7.14/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 184, in default
raise TypeError(repr(o) + " is not JSON serializable")
TypeError: array([ 1.]) is not JSON serializable
The local environment is
$pip show mpld3
Name: mpld3
Version: 0.3
Summary: D3 Viewer for Matplotlib
Home-page: http://mpld3.github.com
Author: Jake VanderPlas
Author-email: jakevdp#cs.washington.edu
License: BSD 3-clause
Location: /usr/local/lib/python2.7/site-packages
and
$python -V
Python 2.7.14
The mpld3 was installed today. Is there an mpld3 versioning issue? Any other suggestions?

Based on a comment from #snakecharmerb I forked from mpld3, entered the suggested fix, and pip installed from my new branch on github.
The fix is here: https://github.com/javadba/mpld3/tree/display_fix . It may be installed via:
python -m pip install --user "git+https://github.com/javadba/mpld3#display_fix"
It works well: the json serialization error is gone and the linkage among the 9 charts functions properly:

For me, the solution given here did not work.
I had a networkx graph to visualize:
import matplotlib.pyplot as plt
import numpy as np
import mpld3
import networkx as nx
G = nx.path_graph(4)
pos = nx.spring_layout(G)
fig, ax = plt.subplots(subplot_kw=dict(facecolor='#EEEEEE'))
scatter = nx.draw_networkx_nodes(G, pos, ax=ax)
nx.draw_networkx_edges(G, pos, ax=ax)
labels = G.nodes()
tooltip = mpld3.plugins.PointLabelTooltip(scatter, labels=labels)
mpld3.plugins.connect(fig, tooltip)
mpld3.show()
Then it gave the "JSON not serializable" error. I found the above link, and tried the fix. The fix essentially says that if the object is of type numpy.ndarray, then change it to list.
But the object type of G.nodes is networkx.classes.reportviews.NodeView, not numpy.ndarray; thus it wasn't working.
So, I modified the file _display.py to add import networkx and added the following 2 lines in the default function in class NumpyEncoder to make it work:
elif isinstance(obj,networkx.classes.reportviews.NodeView):
return list(obj)
Now it works:

Related

mpld3.show() returns Object of type int is not JSON serializable

I want to create a network where you can hover over each label to read it interactively.
I am using jupyter lab, specs are:
Selected Jupyter core packages...
IPython : 7.6.1
ipykernel : 5.1.1
ipywidgets : 7.6.5
jupyter_client : 7.0.6
jupyter_core : 4.8.1
jupyter_server : not installed
jupyterlab : 1.0.2
nbclient : not installed
nbconvert : 5.5.0
nbformat : 4.4.0
notebook : 6.0.0
qtconsole : 4.5.1
traitlets : 4.3.2
When I run this code in a jupyter notebook:
import matplotlib.pyplot as plt
import numpy as np
import mpld3
fig, ax = plt.subplots(subplot_kw=dict(axisbg='#EEEEEE'))
N = 100
scatter = ax.scatter(np.random.normal(size=N),
np.random.normal(size=N),
c=np.random.random(size=N),
s=1000 * np.random.random(size=N),
alpha=0.3,
cmap=plt.cm.jet)
ax.grid(color='white', linestyle='solid')
ax.set_title("Scatter Plot (with tooltips!)", size=20)
labels = ['point {0}'.format(i + 1) for i in range(N)]
tooltip = mpld3.plugins.PointLabelTooltip(scatter, labels=labels)
mpld3.plugins.connect(fig, tooltip)
mpld3.show()
That I obtained from here, a new window opens, with interactive labels, as expected and identical to the example in the hyperlink.
My own data is:
index col_A
0 6840
1 6640
2 823
3 57019
index col_B
0 7431
1 5217
2 7431
3 57019
For a network, these are pairs of node labels like this:
col_A col_B
6840 7431
6640 5217
823 7431
57019 57019
So the output network should have three clusters:
6840-7431-823
6640-5217
57019-57019
When I run this code, which is almost identical to the example code above:
import matplotlib.pyplot as plt
import numpy as np
import mpld3
import mplcursors
import networkx as nx
#G = nx.path_graph(4)
#pos = nx.spring_layout(G)
G = nx.from_pandas_edgelist(final_net,'col_A','col_B',['col_A', 'col_B'])
print(final_net['col_A'][0:10])
print(final_net['col_B'][0:10])
edge_labels = nx.get_edge_attributes(G, "Edge_label")
pos = nx.spring_layout(G)
fig, ax = plt.subplots(subplot_kw=dict(facecolor='#EEEEEE'))
scatter = nx.draw_networkx_nodes(G, pos, ax=ax)
nx.draw_networkx_edges(G, pos, ax=ax)
labels = G.nodes()
tooltip = mpld3.plugins.PointLabelTooltip(scatter, labels=labels)
mpld3.plugins.connect(fig, tooltip)
mplcursors.cursor(hover=True)
mpld3.show()
I do get the correct static image:
But I get an error:
TypeError: Object of type int is not JSON serializable
And the network doesn't open in a new window that I can interact with (ideally the interactive network would remain in jupyter anyway).
I changed the object types to string to see what happened with:
final_net['col_A'] = pd.to_numeric(final_net['col_A'])
final_net['col_B'] = pd.to_numeric(final_net['col_B'])
With the output:
col_A int64
col_B int64
But the error remains the same. When I remove the last line, mpld3.show() , the error disappears, so I just get a static image as an output, with no error, but no interactivity either.
I uninstalled and re-installed with conda as per here (which keeps the same error) and then I dumped to JSON as per here
by doing:
import json
import numpy as np
data = [[6840, 7431], [6640, 5217], [823, 7431],[57019,57019]]
final_net = pd.DataFrame(data, columns = ['col_A', 'col_B'])
class NumpyEncoder(json.JSONEncoder):
""" Special json encoder for numpy types """
def default(self, obj):
if isinstance(obj, np.integer):
return int(obj)
elif isinstance(obj, np.floating):
return float(obj)
elif isinstance(obj, np.ndarray):
return obj.tolist()
return json.JSONEncoder.default(self, obj)
#dumped = json.dumps(final_net, cls=NumpyEncoder)
#with open(path, 'w') as f:
# json.dump(dumped, f)
final_net['col_A'] = json.dumps(final_net['col_A'],cls=NumpyEncoder)
final_net['col_B'] = json.dumps(final_net['col_B'],cls=NumpyEncoder)
When I dump to json and then rerun my network code again, it outputs:
0 "{\"0\":6840,\"1\":6640,\"2\":823,\"3\":57019}"
1 "{\"0\":6840,\"1\":6640,\"2\":823,\"3\":57019}"
2 "{\"0\":6840,\"1\":6640,\"2\":823,\"3\":57019}"
3 "{\"0\":6840,\"1\":6640,\"2\":823,\"3\":57019}"
Name: Entrez Gene Interactor A, dtype: object
0 "{\"0\":7431,\"1\":5217,\"2\":7431,\"3\":57019}"
1 "{\"0\":7431,\"1\":5217,\"2\":7431,\"3\":57019}"
2 "{\"0\":7431,\"1\":5217,\"2\":7431,\"3\":57019}"
3 "{\"0\":7431,\"1\":5217,\"2\":7431,\"3\":57019}"
And this image (which is wrong), and no interactivity.
I'm wonder if someone could show me how to edit my code to make the interactive feature appear (ideally in a jupyter notebook, if not it's ok if it opens in a new window).
The problem seems to be that G.nodes() isn't a list of labels. You can get the node numbers or labels via converting it to a list (list(G.nodes())).
An updated version could look like:
import matplotlib.pyplot as plt
import networkx as nx
import pandas as pd
import numpy as np
import mpld3
final_net = pd.DataFrame({'col_A': [6840, 6640, 823, 57019],
'col_B': [7431, 5217, 7431, 57019]})
G = nx.from_pandas_edgelist(final_net, 'col_A', 'col_B', ['col_A', 'col_B'])
print(final_net['col_A'][0:10])
print(final_net['col_B'][0:10])
edge_labels = nx.get_edge_attributes(G, "Edge_label")
pos = nx.spring_layout(G)
fig, ax = plt.subplots(subplot_kw=dict(facecolor='#EEEEEE'))
scatter = nx.draw_networkx_nodes(G, pos, ax=ax)
nx.draw_networkx_edges(G, pos, ax=ax)
labels = list(G.nodes())
tooltip = mpld3.plugins.PointLabelTooltip(scatter, labels=labels)
mpld3.plugins.connect(fig, tooltip)
mpld3.show()

How to use correctly matplotlib's pcolor?

I have a 2d graph drawn using matplotlib and dataframe.
I followed the accepted answer in this question: How to change pyplot background colour in region of interest?
My code was working as expected until maybe my last arch Linux update.
Since then, my code is not working anymore and I get following error:
[1493 rows x 5 columns]
Traceback (most recent call last):
File "eco.py", line 148, in _show_alert
ax.pcolor(df.index, ax.get_ylim(),df['alert'].values[np.newaxis])
File "/usr/lib/python3.8/site-packages/matplotlib/__init__.py", line 1447, in inner
return func(ax, *map(sanitize_sequence, args), **kwargs)
File "/usr/lib/python3.8/site-packages/matplotlib/axes/_axes.py", line 5821, in pcolor
X, Y, C, shading = self._pcolorargs('pcolor', *args, shading=shading,
File "/usr/lib/python3.8/site-packages/matplotlib/axes/_axes.py", line 5590, in _pcolorargs
Nx = X.shape[-1]
AttributeError: 'list' object has no attribute 'shape'
The code:
cmap = ListedColormap(['white','red'])
ax.pcolor(df.index, ax.get_ylim(),df['alert'].values[np.newaxis],
cmap=cmap, alpha=0.5, linewidth=1, antialiased=True)
Where df is a pandas's dataframe instance, df.index timestamp index, and df['alert'] values that can be 0 or 1 (so I can map red color when alert=1).
The expected final result is a 2d graph (df['val']) with white background, or red background depending on df['alert'].
What am I doing wrong ?
Was I lucky if it was previously working ?
Was the API changed ? How am I supposed to know this kind of stuff if it is the case ?
It is hard to understand what you are doing wrong with the information provided. Here is a simple working example. Try to pinpoint the difference with your implementation, especially the type of the variables.
from matplotlib import dates as mdates
from matplotlib.colors import ListedColormap
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
data = pd.DataFrame({
'date': ['10/25/2005','10/29/2002','01/01/2001','01/01/2000','01/01/1999','01/01/1997'],
'A': [0,5,-1,3,4,0],
'alert': [0,0,0,1,1,1]
})
# convert to type datetime
data['date'] = pd.to_datetime(data['date'])
data = data.set_index('date')
fig, ax = plt.subplots()
cmap = ListedColormap(['white','red'])
ax.plot(data['A'])
ax.set_xlabel('')
plt.xticks(rotation = 30)
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
ax.pcolor(data.index, ax.get_ylim(),data['alert'].values[np.newaxis],
cmap=cmap, alpha=0.5, linewidth=1, antialiased=True)
plt.axhline(y = 0, color = 'black')
plt.tight_layout()

Matplotlib interactive plots crash if mouse scroll used on plot

This issue seems to happen any time I plot data using plt.show() with Matplotlib on my Macbook Pro (OSX 10.13.6). If I create a Pandas dataframe and plot the data with Matplotlib, then show the result on the screen in the interactive window (using plt.show), the window (and matplotlib) will often crash. It will always happen if the mouse gesture for scroll-up or down is done on the screen. Other times it seems to happen at random.
When the plot crashes i get this as a traceback:
Traceback (most recent call last):
File "./plot_lc_vs_gnss.py", line 117, in <module>
main()
File "./plot_lc_vs_gnss.py", line 28, in main
plt.show()
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/matplotlib/pyplot.py", line 253, in show
return _show(*args, **kw)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/matplotlib/backend_bases.py", line 208, in show
cls.mainloop()
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/matplotlib/backends/_backend_tk.py", line 1073, in mainloop
Tk.mainloop()
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/tkinter/__init__.py", line 557, in mainloop
_default_root.tk.mainloop(n)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte
The data I am reading in is a simple CSV that was previously generated by pandas as well. I am generating the plot with a simple script like this:
#!/usr/local/bin/python3
import matplotlib
matplotlib.use('TkAgg')
import json
import os
import numpy as np
import pandas as pd
import pymap3d as pm
import matplotlib.pyplot as plt
def load_csvs():
gnss = pd.read_csv('di3_d4_1017_gnss.csv')
ins = pd.read_csv('di3_d4_1017_ins.csv')
return gnss, ins
def plot_cdf(gnss, ins):
data = [gnss, ins]
plt.figure(figsize=[12,9])
ax = plt.subplot(1,1,1)
for ds in data:
if ds[err].any != np.nan:
dsorted = np.sort(ds['horizontal_error'])
yvals = np.arange(len(dsorted)) / float(len(dsorted) - 1) * 100
ax.plot(dsorted, yvals)
ax.grid()
ax.set_xlabel('Horizontal Error (m)')
ax.set_ylabel('Percent of Epochs')
title = 'Drive Test data \n DI-3 (roof) d4_1017 \n CDF Horizontal Error'
plt.title(title)
plt.legend(['gnss', 'ins'], loc='lower right')
def main():
gnss, ins = load_csvs()
plot_cdf(gnss, ins)
plt.show()
if __name__ == "__main__":
main()
Any advice on how to fix this issue would be greatly appreciated.
I guess by now it does not matter, but this seems to be an unresolved problem under discussion in #9637

Importing matplotlib.pyplot in Rstudio using reticulate

I am unable to import matplotlib.pyplot as plt in Rstudio.
I tried the solutions already available on SO.
Here are my attempts:
I installed reticulate package the devtools install way.
devtools::install_github(rstudio/reticulate)
library(reticulate)
repl_python()
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0,10, 100)
plt.plot(x, x, label = "linear")
plt.legend()
plt.show()
I received the following error -
RuntimeError: module compiled against API version 0xb but this version of numpy is 0xa ImportError: numpy.core.multiarray failed to import
I tried in RMarkdown as well.
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
library(knitr)
library(reticulate)
use_condaenv(condaenv = "python36", conda = "auto", required = FALSE)
```
```{python}
repl_python()
import numpy as np
import matplotlib.pyplot as plt
n = 256
X = np.linspace(-np.pi,np.pi,n,endpoint=True)
Y = np.sin(2*X)
plt.plot (X, Y+1, color='blue', alpha=1.00)
plt.plot (X, Y-1, color='blue', alpha=1.00)
plt.show()
```
Received the following error -
RuntimeError: module compiled against API version 0xb but this version of numpy is 0xa
Traceback (most recent call last):
File "C:\Users\Vidhya\AppData\Local\Temp\Rtmp6vCzV6\chunk-code-13e83c491e61.txt", line 2, in <module>
import matplotlib.pyplot as plt
File "C:\Anaconda3\lib\site-packages\matplotlib\pyplot.py", line 29, in <module>
import matplotlib.colorbar
File "C:\Anaconda3\lib\site-packages\matplotlib\colorbar.py", line 32, in <module>
import matplotlib.artist as martist
File "C:\Anaconda3\lib\site-packages\matplotlib\artist.py", line 15, in <module>
from .transforms import (Bbox, IdentityTransform, TransformedBbox,
File "C:\Anaconda3\lib\site-packages\matplotlib\transforms.py", line 39, in <module>
from matplotlib._path import (affine_transform, count_bboxes_overlapping_bbox,
ImportError: numpy.core.multiarray failed to import
I had similar issues. I did following and it solved. Before that I would like to refer you in following threads from where I got the solution...
Qt platform plugin issue Rstudio
PyQt5 - Failed to load platform plugin "windows". Available platforms are: windows, minimal
Here is what you have to do [change the path according to your system]
In R:-
py_run_string("import os as os")
py_run_string("os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = 'C:/Dev/Anaconda/Library/plugins/platforms'")
np <- import("numpy", as = "np")
plt <- import("matplotlib.pyplot", as = "plt")
x <- np$linspace(0,10, 100)
plt$plot(x, x, label = "linear")
plt$legend()
plt$show()
In repl_python (embedded mode)
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0,10, 100)
plt.plot(x, x, label = "linear")
plt.legend()
plt.show()
Hope this helps... cheers

Can you change iris cube projections in cartopy

I really like the idea that cartopy can automatically plot in different map projections. However, I couldn't figure out how to do with the Iris cubes. As its a sister project, I expected that I might be able to. Is it possible to do something like this?
import iris as I
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
someCube = I.load('someCube.pp')
ax = plt.axes(projection=ccrs.Robinson())
I.plot.contourf(someCube, transform=ccrs.Robinson())
plt.show()
thanks
I took your pseudo code and made it runnable with Iris' sample data:
import iris
import iris.plot as iplt
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
fname = iris.sample_data_path('air_temp.pp')
air_temp = iris.load_cube(fname)
ax = plt.axes(projection=ccrs.Robinson())
iplt.contourf(air_temp, transform=ccrs.Robinson(central_longitude=180))
ax.coastlines()
plt.show()
If you run this code, you will get an exception along the lines of:
Traceback (most recent call last):
File "using_custom_projections.py", line 11, in <module>
iris.plot.contourf(air_temp, transform=ccrs.Robinson())
File "lib/iris/plot.py", line 452, in contourf
result = _draw_2d_from_points('contourf', None, cube, *args, **kwargs)
File "lib/iris/plot.py", line 263, in _draw_2d_from_points
result = _map_common(draw_method_name, arg_func, iris.coords.POINT_MODE, cube, data, *args, **kwargs)
File "lib/iris/plot.py", line 406, in _map_common
assert 'transform' not in kwargs, 'Transform keyword is not allowed.'
AssertionError: Transform keyword is not allowed.
Which is trying to tell you that you do not need to tell it which "transform" (or coordinate system) the cube is in. The reason for that is that an Iris cube should contain full metadata about the underlying data: the coordinate systems is part of that metadata.
So, to get the example to work, you can simply remove the transform keyword argument in your contourf call:
import iris
import iris.plot as iplt
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
fname = iris.sample_data_path('air_temp.pp')
air_temp = iris.load_cube(fname)
ax = plt.axes(projection=ccrs.Robinson(central_longitude=180))
iplt.contourf(air_temp)
ax.coastlines()
plt.show()
There is a similar example in the iris gallery, specifically http://scitools.org.uk/iris/docs/latest/examples/graphics/rotated_pole_mapping.html#rotated-pole-mapping-03 (the very last plot in the example).
HTH,

Categories