1

Let's say at some point in my code, I have following two graphs: i.e. graph_p_changes and graph_p_contrib

line_grapgh_p_changes = df_p_change[['year','interest accrued', 'trade debts', 'other financial assets']].melt('year', var_name='variables',  value_name='p_changes')
graph_p_changes = sns.factorplot(x="year", y="p_changes", hue='variables', data=line_grapgh_p_changes, height=5, aspect=2)
graph_p_changes.set(xlabel='year', ylabel='percentage change in self value across the years')

line_grapgh_p_contrib = df_p_contrib[['year','interest accrued', 'trade debts', 'other financial assets']].melt('year', var_name='variables',  value_name='p_changes')
graph_p_contrib = sns.factorplot(x="year", y="p_changes", hue='variables', data=line_grapgh_p_contrib, height=5, aspect=2)
graph_p_contrib.set(xlabel='year', ylabel='percentage chnage in contribution to total value')

Now at some point later in my code, I just want to display one of the above two graphs. But when I do plt.show(), it displays both of the above graphs in my jupyter notebook. How can I display only one graph at any point in my code.

Muhammad Hassan
  • 4,079
  • 1
  • 13
  • 27

1 Answers1

4

You'll want to refer to the assigned variable for each plot and then add .fig after that to redisplay it in a Jupyter notebook cell.

Specifically, in your case you'd reference graph_p_changes.fig or graph_p_contrib.fig in a cell and execute that cell to see an individual plot again.

This is similar to how you can show Seaborn's ClusterGrids again, see here. Because the title of your question said 'seaborn plots', I'll add for sake of completeness, this doesn't hold for plots like Seaborn's line plot (lineplot) or bar plot (barplot) , that produce AxesSubplot objects. There you use .figure, for example ax.figure to recall most of the examples listed on Seaborn's lineplot documentation. (The suggestion of ax.figure assumes you added assigning the plot to a variable named ax, for example using code like ax = sns.lineplot(....)


Example catplots with code

This is using example code from here and seaborn's catplot documentation (see below) to make two plots. If this code was in one cell and then that cell was run, you'd see two plots in the output below it.

import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline

titanic = sns.load_dataset("titanic")
exercise = sns.load_dataset("exercise")
g = sns.catplot("alive", col="deck", 
                col_wrap=3, data=titanic[titanic.deck.notnull()], 
                kind="count", height=2.5, aspect=.8)

another_plot = sns.catplot(x="time", y="pulse", hue="kind", data=exercise)

Later, each can be displayed again individually as output of other cells with g.fig or another_plot.fig, depending on which plot you want to show.


Additionaly, I'll suggest to improve your long-term code viability, you may want to move on to using catplot in your plotting calls as that is what factorplot is now called in seaborn. See here where it says "factorplot still exists and will pass its arguments through to catplot() with a warning. It may be removed eventually, but the transition will be as gradual as possible."

UPDATE:

OP commented that what was desired was code allowing interspersed stdout/stderr output with plots at precise points among that stream and not just at the end.

For some reason, Seaborn plots (even simple line plots) don't seem to get 'captured' correctly with io.capture_output(), and so I had to use the %%capture cell magic command in the producing cell and combine the output in a separate cell. However, Plotly plots I tried based on example code are captured by io.capture_output() and allow facile intermixing all in the same cell. This is all illustrated in an example notebook available here; it is best viewed in static form here at nbviewer because nbviewer renders the Plotly plots while GitHub doesn't. The top of that notebook includes a link where you can launch an active Jupyter session where it will run.

Update related to this UPDATE:
In an insightful answer to 'seaborn stop figure from being visualized', ffrosch suggests you "can temporarily disable/enable the inline creation with plt.ioff() and plt.ion()." This may offer yet another way to fine-tune when Seabor plots show among the output and/or offer another way to constrain ouput since %%capture cell magic worked yet io.capture_output() did not. (I have yet to try this.)

Wayne
  • 6,607
  • 8
  • 36
  • 93
  • Referring to your code, let's say in your cell, after this line: "another_plot = . . . " you have 100 lines of code. Now at line no 101, you want to display just plot "g". After that there are 100 more lines of code and then you want to display plot "another_plot". How can you achieve that. Because in my code when I do, ''plt.show()" in a cell it displays both the plots. – Muhammad Hassan Feb 18 '20 at 04:28
  • 1
    I think I get more of what you mean, & there's a lot of ways to go depending on what you are really trying to accomplish. But first, it clearly sounds like you don't want to use `plt.show()`? Have you tested without it? You'll note in the Seaborn documentation they don't use it. It shouldn't be necessary for modern Jupyter notebooks. Remove it and invoke the plots when you want them to show. I suspect though you see the plots & they are at the end of the output, right? And these first & 2nd blocks of 100 lines of code each produce some output that you need the plots interspersed between? – Wayne Feb 18 '20 at 15:56
  • 1
    Hopefully, you'll clarify further based on my questions above. But based only on what you last wrote, one aspect I am questioning is why you are doing things the way you describe? It sounds like you are trying to run a moderately-sized script in a single notebook cell and control how the output flows. While that certainly can be accomplished, the most direct route is to simply use the structure of the notebook to control how the output flows. Make your code either in multiple cells or in function(s) and invoke the plot when you want to see it. This may necessitate it be in its own cell. – Wayne Feb 18 '20 at 16:04
  • You completely understood what I meant or what I want to accomplish.Have you tested without plt.show()? Yes I tested, but in that case it will show all plots at the end of the output. – Muhammad Hassan Feb 19 '20 at 04:53
  • I wanted to do all this just to get the output in a particular format. But I think there is no such way of doing this except that I split my code in multiple cells. right? – Muhammad Hassan Feb 19 '20 at 04:57
  • 1
    You should be able to use a 'capture' to prevent the output you see at the end of the output without `plt.show()` and then show it when you want even from one single cell. Before I explained that, I wanted to make sure I fully understood what you wanted to do since it is more advanced than just splitting into multiple cells. I'll update my answer illustrating that. – Wayne Feb 19 '20 at 16:26
  • 1
    Well Seaborn doesn't play well with the capture approach I usually use to capture and control output in a single cell. It works with Plotly plots but with Seaborn I needed two cells. I posted the notebook illustrating this [here](https://gist.github.com/fomightez/7c7e4ba777f5084b334c4407453e8dfb). – Wayne Feb 19 '20 at 21:57
  • 1
    What I updated with is best viewed in static form [here](https://gist.github.com/fomightez/7c7e4ba777f5084b334c4407453e8dfb). It shows all the plots where as the gist site doesn't. – Wayne Feb 19 '20 at 22:36
  • I should note that `io.capture_output()` not capturing/suppressing seaborn might be a temporary situation. I think because usually people want to see the plot a lot of effort goes into making it just work. Someone could notice that it is circumventing that particular capture soon and it would be addressed. Or we should be using the `capture.RichOutput()` that I was not having luck using. – Wayne Feb 20 '20 at 16:22
  • There's a related question about [Seaborn plots here](https://stackoverflow.com/q/72532367/8508004) and someone mentions using `%%capture`. A thorough answer for that one used `plt.ioff()` to not display output. – Wayne Jun 07 '22 at 19:21
  • What if i want to display a lineplot later on? lineplot does not have fig level, only axes level – Melvin Calvin Apr 05 '23 at 08:13
  • Right. That's covered at the end of the third paragraph with, "... this doesn't hold for plots like Seaborn's line plot (`lineplot`) or bar plot (`barplot`) , that produce `AxesSubplot` objects. There you use `.figure`, for example `ax.figure` to recall most of the examples listed on Seaborn's lineplot documentation." You'll still need to assign a variable for the plot, for example, `ax = sns.lineplot(...`. Maybe I should make the fact the assignment is still needed more clear. – Wayne Apr 05 '23 at 14:07