75

Is there an existing way to get json.dumps() output to appear as "pretty" formatted JSON inside ipython notebook?

Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
Kyle Brandt
  • 26,938
  • 37
  • 124
  • 165
  • shortest way is to use `pprint()` to print the JSON (`from pprint import pprint`) – PJ_ Apr 24 '23 at 21:19

8 Answers8

114

json.dumps has an indent argument, printing the result should be enough:

print(json.dumps(obj, indent=2))
filmor
  • 30,840
  • 6
  • 50
  • 48
  • 11
    what about the colors in the output? – ganqqwerty Sep 03 '15 at 09:49
  • however Chinese character messed up with Unicode in this approach – Luk Aron Nov 28 '19 at 10:26
  • 1
    That's simply not true. Python's `json.dumps` defaults to `ensure_ascii=True` which escapes Chinese (or actually: any non-ASCII) code-point. Use `print(json.dumps(obj, indent=2, ensure_ascii=False))` and you'll get them unescaped. – filmor Nov 28 '19 at 13:41
86

This might be slightly different than what OP was asking for, but you can do use IPython.display.JSON to interactively view a JSON/dict object.

from IPython.display import JSON
JSON({'a': [1, 2, 3, 4,], 'b': {'inner1': 'helloworld', 'inner2': 'foobar'}})

Edit: This works in Hydrogen and JupyterLab, but not in Jupyter Notebook or in IPython terminal.

Inside Hydrogen:

enter image description here enter image description here

Kyle Barron
  • 2,452
  • 22
  • 17
41
import uuid
from IPython.display import display_javascript, display_html, display
import json

class RenderJSON(object):
    def __init__(self, json_data):
        if isinstance(json_data, dict):
            self.json_str = json.dumps(json_data)
        else:
            self.json_str = json_data
        self.uuid = str(uuid.uuid4())

    def _ipython_display_(self):
        display_html('<div id="{}" style="height: 600px; width:100%;"></div>'.format(self.uuid), raw=True)
        display_javascript("""
        require(["https://rawgit.com/caldwell/renderjson/master/renderjson.js"], function() {
        document.getElementById('%s').appendChild(renderjson(%s))
        });
        """ % (self.uuid, self.json_str), raw=True)

To ouput your data in collapsible format:

RenderJSON(your_json)

enter image description here

Copy pasted from here: https://www.reddit.com/r/IPython/comments/34t4m7/lpt_print_json_in_collapsible_format_in_ipython/

Github: https://github.com/caldwell/renderjson

Shankar ARUL
  • 12,642
  • 11
  • 68
  • 69
  • I cannot get it to work on Jupyter 1.0. Any idea why ? Javascript console says : "SyntaxError: Unexpected token <" – Pierre Carbonnelle Dec 13 '16 at 10:59
  • There is a problem in the code. Line 10 should be changed to ```self.json_str = json_data```. It solves the problem reported by @user474491 . – Hassan Dec 22 '16 at 09:51
  • @Hassan: Fixed! Thanks for the suggestion. – bskaggs Dec 26 '16 at 18:34
  • 1
    I've update a few issues and got this to work in the latest Jupyter Notebook, including @user474491 's and @Hassan 's suggestions, I also added an explicit call to `_ipython_display_()` in the `__init__()` to ensure that we can safely interleave calls to python's native `print()` and `RenderJSON()` and still get this to work https://gist.github.com/t27/48b3ac73a1479914f9fe9383e5d45325 – Tarang Shah Apr 11 '18 at 06:14
  • It will be even better if this accepts `list` type, since `caldwell/renderjson` is totally capable of rendering json arrays – Huy Le Jul 17 '18 at 10:15
  • 1
    I just get "Javascript Error: require is not defined". – andy Jan 02 '23 at 12:43
  • I get a possibly similar error as @andy, though it says "Javascript Error: Can't find variable: require" – Danny Kaufman Jan 10 '23 at 23:22
8

I am just adding the expanded variable to @Kyle Barron answer:

from IPython.display import JSON
JSON(json_object, expanded=True)
Joe Cabezas
  • 1,397
  • 3
  • 15
  • 21
4

I found this page looking for a way to eliminate the literal \ns in the output. We're doing a coding interview using Jupyter and I wanted a way to display the result of a function real perty like. My version of Jupyter (4.1.0) doesn't render them as actual line breaks. The solution I produced is (I sort of hope this is not the best way to do it but...)

import json

output = json.dumps(obj, indent=2)

line_list = output.split("\n")  # Sort of line replacing "\n" with a new line

# Now that our obj is a list of strings leverage print's automatic newline
for line in line_list:
    print line

I hope this helps someone!

John Carrell
  • 1,662
  • 3
  • 21
  • 31
0

For Jupyter notebook, may be is enough to generate the link to open in a new tab (with the JSON viewer of firefox):

from IPython.display import Markdown
def jsonviewer(d):
   f=open('file.json','w')
   json.dump(d,f)
   f.close()
   print('open in firefox new tab:')
   return Markdown('[file.json](./file.json)')

jsonviewer('[{"A":1}]')
'open in firefox new tab:

file.json

restrepo
  • 479
  • 3
  • 14
0

Just an extension to @filmor answer(https://stackoverflow.com/a/18873131/7018342).

This encodes elements that might not compatible with json.dumps and also gives a handy function that can be used just like you would use print.

import json
class NpEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, np.integer):
            return int(obj)
        if isinstance(obj, np.floating):
            return float(obj)
        if isinstance(obj, np.ndarray):
            return obj.tolist()
        if isinstance(obj, np.bool_):
            return bool(obj)
        return super(NpEncoder, self).default(obj)

def print_json(json_dict):
    print(json.dumps(json_dict, indent=2, cls=NpEncoder))

Usage:

json_dict = {"Name":{"First Name": "Lorem", "Last Name": "Ipsum"}, "Age":26}
print_json(json_dict)
>>>
{
  "Name": {
    "First Name": "Lorem",
    "Last Name": "Ipsum"
  },
  "Age": 26
}
0

For some uses, indent should make it:

print(json.dumps(parsed, indent=2))

A Json structure is basically tree structure. While trying to find something fancier, I came across this nice paper depicting other forms of nice trees that might be interesting: https://blog.ouseful.info/2021/07/13/exploring-the-hierarchical-structure-of-dataframes-and-csv-data/.

It has some interactive trees and even comes with some code including linking to this question and the collapsing tree from Shankar ARUL.

Other samples include using plotly Here is the code example from plotly:

import plotly.express as px
fig = px.treemap(
    names = ["Eve","Cain", "Seth", "Enos", "Noam", "Abel", "Awan", "Enoch", "Azura"],
    parents = ["", "Eve", "Eve", "Seth", "Seth", "Eve", "Eve", "Awan", "Eve"]
)
fig.update_traces(root_color="lightgrey")
fig.update_layout(margin = dict(t=50, l=25, r=25, b=25))
fig.show()

enter image description here enter image description here

And using treelib. On that note, This github also provides nice visualizations. Here is one example using treelib:

#%pip install treelib
from treelib import Tree

country_tree = Tree()
# Create a root node
country_tree.create_node("Country", "countries")

# Group by country
for country, regions in wards_df.head(5).groupby(["CTRY17NM", "CTRY17CD"]):
    # Generate a node for each country
    country_tree.create_node(country[0], country[1], parent="countries")
    # Group by region
    for region, las in regions.groupby(["GOR10NM", "GOR10CD"]):
        # Generate a node for each region
        country_tree.create_node(region[0], region[1], parent=country[1])
        # Group by local authority
        for la, wards in las.groupby(['LAD17NM', 'LAD17CD']):
            # Create a node for each local authority
            country_tree.create_node(la[0], la[1], parent=region[1])
            for ward, _ in wards.groupby(['WD17NM', 'WD17CD']):
                # Create a leaf node for each ward
                country_tree.create_node(ward[0], ward[1], parent=la[1])

# Output the hierarchical data
country_tree.show()

enter image description here

I have, based on this, created a function to convert json to a tree:

from treelib import Node, Tree, node
def json_2_tree(o , parent_id=None, tree=None, counter_byref=[0], verbose=False, listsNodeSymbol='+'):
    if tree is None:
        tree = Tree()
        root_id = counter_byref[0]
        if verbose:
            print(f"tree.create_node({'+'}, {root_id})")
        tree.create_node('+', root_id)
        counter_byref[0] += 1
        parent_id = root_id
    if type(o) == dict:
        for k,v in o.items():
            this_id = counter_byref[0]
            if verbose:
                print(f"tree.create_node({str(k)}, {this_id}, parent={parent_id})")
            tree.create_node(str(k), this_id, parent=parent_id)
            counter_byref[0]  += 1
            json_2_tree(v , parent_id=this_id, tree=tree, counter_byref=counter_byref, verbose=verbose, listsNodeSymbol=listsNodeSymbol)
    elif type(o) == list:
        if listsNodeSymbol is not None:
            if verbose:
                print(f"tree.create_node({listsNodeSymbol}, {counter_byref[0]}, parent={parent_id})")
            tree.create_node(listsNodeSymbol, counter_byref[0], parent=parent_id)
            parent_id=counter_byref[0]
            counter_byref[0]  += 1        
        for i in o:
            json_2_tree(i , parent_id=parent_id, tree=tree, counter_byref=counter_byref, verbose=verbose,listsNodeSymbol=listsNodeSymbol)
    else: #node
        if verbose:
            print(f"tree.create_node({str(o)}, {counter_byref[0]}, parent={parent_id})")
        tree.create_node(str(o), counter_byref[0], parent=parent_id)
        counter_byref[0] += 1
    return tree

Then for example:

import json
json_2_tree(json.loads('{"2": 3, "4": [5, 6]}'),verbose=False,listsNodeSymbol='+').show()       

gives:

+
├── 2
│   └── 3
└── 4
    └── +
        ├── 5
        └── 6

While

json_2_tree(json.loads('{"2": 3, "4": [5, 6]}'),listsNodeSymbol=None).show()       

Gives

+
├── 2
│   └── 3
└── 4
    ├── 5
    └── 6

As you see, there are different trees one can make depending on how explicit vs. compact he wants to be. One of my favorites, and one of the most compact ones might be using yaml:

import yaml
j = json.loads('{"2": "3", "4": ["5", "6"], "7": {"8": "9"}}')
print(yaml.dump(j, sort_keys=False))

Gives the compact and unambiguous:

'2': '3'
'4':
- '5'
- '6'
'7':
  '8': '9'
ntg
  • 12,950
  • 7
  • 74
  • 95