英文:
Display HTML class not showing inside an if-else block in Jupyter Notebook
问题
I'll provide translations for the code parts you provided:
# Handy class for DataFrame viz
class display(object):
'''
Display HTML representation of multiple objects
'''
template = '''<div style="float: left; padding: 10px;">
<p style='font-family:"Courier New", Courier, monospace'>{0}</p>{1}
</div>'''
def __init__(self, *args):
self.args = args
def _repr_html_(self):
return '\n'.join(self.template.format(a, eval(a)._repr_html_()) for a in self.args)
def __repr__(self):
return '\n\n'.join(a + '\n' + repr(eval(a)) for a in self.args)
这个类用于在.ipynb文件中表示数据框。
This class is used to represent dataframes in an .ipynb file:
import pandas as pd
# Handy class for DataFrame viz
# 创建一个包含3行5列的示例数据框
df = pd.DataFrame({
'A': [1, 2, 3],
'B': [4, 5, 6],
'C': [7, 8, 9],
'D': [10, 11, 12],
'E': [13, 14, 15]
})
# 显示数据框
display('df')
这个类在if-else块内部不起作用,我不明白为什么。
This class is not working inside an if-else block, and I don't understand why.
英文:
I'm using this class to represent the dataframes in a .ipynb file:
# Handy class for DataFrame viz
class display(object):
'''
Display HTML representation of multiple objects
'''
template = '''<div style="float: left; padding: 10px;">
<p style='font-family:"Courier New", Courier, monospace'>{0}</p>{1}
</div>'''
def __init__(self, *args):
self.args = args
def _repr_html_(self):
return '\n'.join(self.template.format(a, eval(a)._repr_html_()) for a in self.args)
def __repr__(self):
return '\n\n'.join(a + '\n' + repr(eval(a)) for a in self.args)
This class is not working inside an if-else block and I don't understand why.
Can anyone give an explanation? Thx in advance!
Chunk to replicate the issue:
import pandas as pd
# Handy class for DataFrame viz
# Create a sample DataFrame with 3 rows and 5 columns
df = pd.DataFrame({
'A': [1, 2, 3],
'B': [4, 5, 6],
'C': [7, 8, 9],
'D': [10, 11, 12],
'E': [13, 14, 15]
})
# Display the DataFrame
display('df')
>>>
df
A B C D E
0 1 4 7 10 13
1 2 5 8 11 14
2 3 6 9 12 15
inside = True
if inside:
display('df')
>>>
答案1
得分: 1
I have translated the content you provided:
我认为这可能是因为if inside
的缩进使其不在单元格的最后一行的最外层点上,因此IPython/Jupyter不使用InteractiveShell来通过其特殊处理单元格中最后一个未缩进的对象的方式来“显示”它,查看这里的last_expr
是InteractiveShell.ast_node_interactivity
的默认值在这里。同样,假设您在一个单元格中运行以下内容:
a = 4
a
这将显示4
为Out
。
但如果您在下一个单元格中执行以下操作,它将不会显示4
:
inside = True
if inside:
a
IPython/Jupyter对最后一行上的项目的精美显示处理不会被应用,因为它不是该行上评估的最外层项目,因此不会传递给IPython的精美表示处理。(或者至少这是我对此的理解。参见Thomas K的解释关于仅在表达式位于for
循环中且因此缩进方式与您的if-else
中的方式类似时才显示单元格末尾的裸表达式。)我认为这与您的操作方式相似,也许?
但这个方法有效:
from IPython.display import display
inside = True
if inside:
display(a)
您可以使用这种方法来强制应用它在将a
放入单元格并运行它时所应用的精美处理方式。
或者,如果您首先调整InteractiveShell.ast_node_interactivity
的设置,您可以使以下内容起作用:
inside = True
if inside:
a
在尝试在单独的单元格中执行此操作之前,您可以运行以下任一内容:
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "last"
-或-
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
(因为它需要在运行要新设置生效的单元格之前运行和应用,所以您不能只是将代码添加到要运行if inside:
的同一单元格中。)
选项A: 调整InteractiveShell.ast_node_interactivity
来尝试修复您的操作:
因此,为了使您的原始示例代码起作用,您可以首先运行以下内容作为单元格,然后再运行您的原始帖子中的inside = True
代码块:
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "last"
备选选项B: 使用IPython的display来尝试修复您的操作:
因此,为了使您的DataFrame显示类的版本起作用,让我们不要隐藏IPython的display
,因为我们将需要它。所以,将这段代码放在一个单元格中:
class spec_display(object):
'''
Display HTML representation of multiple objects
'''
template = '''<div style="float: left; padding: 10px;">
<p style='font-family:"Courier New", Courier, monospace'>{0}</p>{1}
</div>'''
def __init__(self, *args):
self.args = args
def _repr_html_(self):
return '\n'.join(self.template.format(a, eval(a)._repr_html_()) for a in self.args)
def __repr__(self):
return '\n\n'.join(a + '\n' + repr(eval(a)) for a in self.args)
然后,作为单独的单元格,这可以像您的原始示例一样工作:
import pandas as pd
# 用于DataFrame可视化的方便类
# 创建一个包含3行和5列的示例DataFrame
df = pd.DataFrame({
'A': [1, 2, 3],
'B': [4, 5, 6],
'C': [7, 8, 9],
'D': [10, 11, 12],
'E': [13, 14, 15]
})
# 显示DataFrame
spec_display('df')
除了现在,在另一个单元格中,无法工作的内容可以通过明确调用IPython的display
来使其工作,就像我们可以使用它来在一个单元格中打印多个DataFrame并添加标题一样(我会回到这一点):
from IPython.display import display
inside = True
if inside:
display(spec_display('df'))
最后,我提到了您可以使用IPython的display
来在一个单元格中打印多个DataFrame并添加标题,所有这些都在一个输出单元格中完成。 (我提到这一点是因为我在您的代码评论中看到了“显示多个对象的HTML表示”)。这是一个示例:
import pandas as pd
df1 = pd.DataFrame({
'A': [1, 2, 3],
'B': [4, 5, 6],
'C': [7, 8, 9],
'D': [10, 11, 12],
'E': [13, 14, 15]
})
df2 = pd.DataFrame({
'A': [1, 2, 3],
'B': [4, 5, 6],
'C': [7, 8, 9],
'D': [10, 11, 12],
'E': [13, 14, 15]
})
from IPython.display import display, HTML
display(HTML('<b>Dataframe One:</b>'))
display(df1)
display(HTML('<b>Dataframe Two:</b>'))
display(df2)
我们可以告诉IPython如何处理事情,而不是依赖它通
英文:
I think it may be because the indentation of the if inside
if-else makes it not on the outermost point on the last line of the cell so IPython/Jupyter doesn't use the InteractiveShell to 'show' it using it's special handling of the last unindented object in a cell, see how last_expr
is the default for InteractiveShell.ast_node_interactivity
here. In the same way as this... Say you run the following in a cell:
a = 4
a
That's going to show 4
as Out
.
But if you do the following in the next cell, it isn't going to show 4
:
inside = True
if inside:
a
The fancy display handling that IPython / Jupyter applies to the item on the last line doesn't get applied because it's not the outermost item evaluated on that line and so doesn't get passed to IPython's fancy representational handling. (Or at least that is how I think about it. See Thomas K's explanation here about how it only shows the bare expression at the end of the cell when the expressions are in a for
loop and hence indented similar to in your if-else
.) And I think that mirrors what you were doing, maybe?
But this works:
from IPython.display import display
inside = True
if inside:
display(a)
You can do that to force applying the fancy handling it would apply if you just put a
in a cell and ran it.
Or if you first adjust the setting for `InteractiveShell.ast_node_interactivity you can get the following to work:
inside = True
if inside:
a
Before trying that in separate cell, you run either the following:
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "last"
-OR-
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
(Because it needs to be run & applied before you run the cell you want to the new settings to be effective for, you cannot just add the code to adjust InteractiveShell.ast_node_interactivity
in the same cell where you are going to run if inside:
.)
OPTION A: adjust InteractiveShell.ast_node_interactivity
to try to fix what you are doing:
And so to make your original example code work, you have the option of first running the following as a cell itself prior to running your inside = True
block of code in your original post:
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "last"
Alternative OPTION B: Applying the use if IPython's display to try to fix what you are doing:
So to make your version of the dataframe display class work, let's not shadow IPython's display
because we'll need it. So make this a cell:
class spec_display(object):
'''
Display HTML representation of multiple objects
'''
template = '''<div style="float: left; padding: 10px;">
<p style='font-family:"Courier New", Courier, monospace'>{0}</p>{1}
</div>'''
def __init__(self, *args):
self.args = args
def _repr_html_(self):
return '\n'.join(self.template.format(a, eval(a)._repr_html_()) for a in self.args)
def __repr__(self):
return '\n\n'.join(a + '\n' + repr(eval(a)) for a in self.args)
Then as a separate cell, this works like your original:
import pandas as pd
# Handy class for DataFrame viz
# Create a sample DataFrame with 3 rows and 5 columns
df = pd.DataFrame({
'A': [1, 2, 3],
'B': [4, 5, 6],
'C': [7, 8, 9],
'D': [10, 11, 12],
'E': [13, 14, 15]
})
# Display the DataFrame
spec_display('df')
Except now in another cell, what you see not working can be made to work by explicitly invoking IPython's display
, just as we can use that to print multiple dataframes in one cell and add titles (I'll come back to that):
from IPython.display import display
inside = True
if inside:
display(spec_display('df'))
Finally, I mentioned above you can use IPython's display
to print multiple dataframes from code in one cell and add titles, all in one output cell. (I bring this up because I see among the comments of your code, "Display HTML representation of multiple objects".) Example of that:
import pandas as pd
df1 = pd.DataFrame({
'A': [1, 2, 3],
'B': [4, 5, 6],
'C': [7, 8, 9],
'D': [10, 11, 12],
'E': [13, 14, 15]
})
df2 = pd.DataFrame({
'A': [1, 2, 3],
'B': [4, 5, 6],
'C': [7, 8, 9],
'D': [10, 11, 12],
'E': [13, 14, 15]
})
from IPython.display import display, HTML
display(HTML('<b>Dataframe One:</b>'))
display(df1)
display(HTML('<b>Dataframe Two:</b>'))
display(df2)
We can tell IPython how to handle things and not rely on the special handling it usually just applies to the unindented final object on the last line.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论