Python on windows, open plot windows next to each other - python

I am using EPD-python2.7 on windows7. In my python program I end up creating 4-5 figures in separate plot windows. By default the plot windows get stacked on top of each other. Every time I have to drag and replace each of these windows away and distribute over the screen area.
(Q1) Is there any way to set it automatically to have plot windows created next to each other? As shown below in the attached image (it is the screenshot of my second external screen).
(Q2) I have a second (extra) screen, and ideally I would like to have the plot windows created next to each other the second screen, when every time I run my program

You can choose the location of your plot but it is dependant on backend. To check this,
import matplotlib
matplotlib.get_backend()
and then see this answer for various ways to adjust.
For example, this works for me on linux with Qt4Agg,
import matplotlib.pyplot as plt
#Choose the correct dimensions for your first screen
FMwidth = 1280
FMheight = 1024
#Choose the correct dimensions for your second screen
SMwidth = 1280
SMheight = 1024
fm = plt.get_current_fig_manager()
#Works with QT on linux
fm.window.setGeometry(FMwidth,0,SMwidth,SMheight)
This may be better for windows
fm.window.wm_geometry("+500+0")
You may also be able to get the screen size(s) from,
from win32api import GetSystemMetrics
width = GetSystemMetrics(0)
weight = GetSystemMetrics(1)
You can easily create a counter which increments whenever you create a plot and adjusts this specified position so the next plot is next to the previous one each time. However, the size and layout are much easier if you use subplots, for example to set up your 2 by 3 grid,
#Setup 2 by 3 grid of subplots
fig, axs = plt.subplots(2,3,figsize=(width,height))
axs[0,0].plot(x, np.sinc(x))
axs[1,0].hist(y)
etc
You can then use your counter to specify which plot you are currently using and increment this whenever you plot.

I had the same question. What wasn't obvious for me when I looked through the answers is that when you have a second monitor, you can get to it by just using coordinates that are relative to your first monitor. For example, I have a 4k monitor above my 1080p primary monitor, and I get put figures onto it by using negative values for the y position.
mgr = plt.get_current_fig_manager()
mgr.window.move(-400,-2000)
plt.show()
Apparently it knows my monitor arrangement from Windows.

Related

How to plot to a specific monitor when using multiple displays?

Does anyone know how to change the setting of plotting to the same monitor as the mouse cursor is to a specific monitor?
I have multiple monitors and one that is dedicated for graphs, but I always need to move my mouse there quickly to make sure that the plots appear there.
How can I fix this annoying issue?
Additional information that might be important:
The Python library is Matplotlib.
The display setting is "extended" mode.
I've found some workaround for this issue. Not an optimal solution, but worked for me.
I am using matplotlib backend: Qt5Agg
The workaround that I found is to move the window to a specific location and then maximize it. The location to move to would be anywhere within the display that you want the figure to appear in.
fig = plt.figure()
fig.canvas.manager.window.move(0,0)
figManager = plt.get_current_fig_manager()
figManager.window.showMaximized()
plt.plot(range(10))
plt.show()
In my case, I wanted the figures to be maximized anyway, but for those who don't want that, just moving the window using this function might be enough:
fig.canvas.manager.window.move(0,0)
The coordinates (0,0) were the corner coordinates of my main display. You can manually find what are the correct ones for your setup.
You can also set both, the position and the size of the figures manually using this approach:
fig = plt.figure()
mngr = plt.get_current_fig_manager()
posX, posY, sizeX, sizeY = (0,30, 1024, 768)
mngr.window.setGeometry(posX, posY, sizeX, sizeY)
plt.plot(range(10))
plt.show()
Thank you all for your replies.
If anyone finds a better solution, please post it here.

Tkinter DPI bug depends on how import is entered?

I have a weird question. In essence: why does the way I enter the pyplot import line into iPython influence my plot?!
Try this (on Windows 10):
Use a high-DPI main monitor set to 200%
Start a fresh iPython console
Enter the three blocks of code below one by one, using any of these ways for any block:
just typing, OR
pasting: pressing Ctrl+V, OR
pasting: clicking the right mouse button, OR
pressing Up to get it from history
To execute each block, just press Enter
Check whether the whole axis is visible
Close iPython and try again
The minimal reproducible example:
import matplotlib as mpl
mpl.use('TkAgg')
import matplotlib.pyplot as plt
from ctypes import windll
windll.shcore.SetProcessDpiAwareness(2)
fig = plt.figure()
w = fig.canvas.manager.window
print(w.winfo_screenwidth(), w.winfo_screenheight())
w.wm_geometry('1600x800+60+0')
fig.canvas.flush_events()
plt.plot(1, 'x')
plt.show(block=False)
Now the result depends on how the first two blocks have been entered. If one or both of them used option 1 or 2, an incorrect monitor size is reported (1920x1080), but I do get a 'correct' plot (with tiny fonts):
If both import lines have been entered using option 3 or 4 however, the reported monitor size is correct (3840x2160), but I get incorrectly sized/zoomed plots (with normal font size):
The behavior depends on how import lines (or the 'run script' they are in) are entered!? Not how they are run, that's just Enter.
Any idea what causes this? Or how to fix it? Other than remembering to always do Ctrl+V instead of history or right click...
Is this a bug I can report somewhere?
Changing the window size manually a bit afterwards makes the axis fit inside the window. But I would like to script it. And the manual resize does not fix all differences: options 1 and 2 keep using tiny fonts.
Explicitly resetting SetProcessDpiAwareness(0) prevents the issue (1 and 2 keep it): monitor reported as 1920x1080, axes fit inside figure, but a larger window and normal size fonts.
Specifying dpi=192 (or something) explicitly with plt.figure() does not help or change anything.
The used backend is the TkAgg Windows default. The exact same happens with TkCairo. The WxAgg and QtAgg alternatives work ok, using window.SetClientSize(1600, 800) resp. manager.resize(1600, 800) (they work like SetProcessDpiAwareness(0)). So I guess the issue is specific to tkinter.
Using python.exe (instead of ipython.exe) always shows the incorrect version. AFAICS I have not changed the High DPI compatibility settings for iPython.
Almost all differences are gone when I do this:
fig.dpi = windll.user32.GetDpiForWindow(w.winfo_id()) / 0.96
This leaves w.winfo_screenwidth/height() halved and small tool buttons when using options 1 and 2. But the window is 1600 pixels wide as specified (758 resp. 728 high, due to the button bar), fonts are readable (200% as configured in Windows) and the axes fit inside the figure.
I must remember not to use dpi= with plt.figure(), because that messes things up again.
I'm still curious where the difference comes from, but this way I can use the default Tk backend without issues.

Python Pandas plot command produces small images on high resolution display

I am using the following line of code in my python application.
df['Close'].plot()
The figure produced by this code is very small on my high resolution display (Microsoft Surface Studio). I have looked at the documentation for the pandas plot command and matplotlib but have not found any relevant settings. Any help appreciated.
I would guess that you want to leave the figure size constant but change the dpi (dots per inch).
Somewhere on top of your script or notebook add
import matplotlib.pyplot as plt
plt.rcParams["figure.dpi"] = 144
Change 144 to your liking. (Note that multiples of 72 usually give nice lines).
The figsize parameter is what you're after.
df['Close'].plot(figsize=(20,10))
If you are in a Jupyter Notebook, there may be an issue where the notebook shrinks figures to fit in the cell output as .plot(figsize=x,y) increases the size. You will notice the text getting smaller but the plot seems to stay the same size, as you increase the figsize parameters.

Getting matplotlib to render points clicked with a mouse.

I am new to Gui programming, so if this question has been repeated elsewhere using proper terminology I apologize.
Is it possible to make interactive geometric animations with matplotlib? In particular, I want to embed an interactive Matplotlib window within a Tkinter frame to test out several variants of the same algorithm.
Here is a typical usage scenario for which I want to write an interactive
program as described above: Say I want to test a triangulation algorithm for point-sets in the 2-d plane.
When I run my new_triangulation_algorithm.py script, I would like to open up an interactive tkinter frame having an embedded matplotlib window, where the user "mouses-in" his/her points by clicking on, say, 20 different points -- every time a point is selected, a thick blue dot appears at that position. I know Matplotlib "knows" the coordinates of the point when I hover my mouse cursor over it since I always see it displayed in the status bar of my plots.
But I don't know how to input a point at that position with a mouse.
The second panel of my Tkinter frame would then contain several buttons, each button corresponding a different triangulation algorithm which I would like to animate on a given point set.
As the algorithm proceeds, I would like the matplotlib window to get refreshed to show the current state of the algorithm. I presume I would have to use Matplotlib's animation feature to do this, but I am not sure about
this since Matplotlib will have to be embedded in a Tkinter frame.
In future, I would like not only to input points, but also segments, circles, rectangles, but I would want to master a basic example with points
as described above.
This example might be a start. Its backend independend. To add your own buttons you might want to have a look at matplotlibs NavigationToolbar class. There are backend specific implementations like NavigationToolbar2QTAgg. You could inherit the Tk version and add some controls.
from matplotlib import pyplot
import numpy
x_pts = []
y_pts = []
fig, ax = pyplot.subplots()
line, = ax.plot(x_pts, y_pts, marker="o")
def onpick(event):
m_x, m_y = event.x, event.y
x, y = ax.transData.inverted().transform([m_x, m_y])
x_pts.append(x)
y_pts.append(y)
line.set_xdata(x_pts)
line.set_ydata(y_pts)
fig.canvas.draw()
fig.canvas.mpl_connect('button_press_event', onpick)
pyplot.show()

Plotting for a large number of time series data points using matplotlib

I've collected a sensor data every 5 minutes for a month (30 days).
That means, I have a timeseries data with 288*30 data points in total.
I'd like to scatterplot the data (x-axis: time, y-axis: sensor value).
the following code is for test.
import pandas as pd
from matplotlib import pyplot as plt
import numpy as np
# generate time series randomly (length: 1 month)
rng=pd.date_range("2015-11-11",periods=288*30,freq="5min")
ts=pd.Series(np.random.randn(len(rng)),rng)
nr=3
nc=1
fig=plt.figure(1)
fig.subplots_adjust(left=0.04,top=1,bottom=0.02,right=0.98,wspace=0.1,hspace=0.1)
for i in range(3):
ctr=i+1
ax=fig.add_subplot(nr,nc,ctr)
ax.scatter(ts.index,ts.values)
ax.set_xlim(ts.index.min(),ts.index.max())
plt.show()
I've generated random time series data having 288*30 observations and tried to draw it in scatter plot. However, as you can see, it is impossible to analyze the figure.
I want to redraw it satisfying the following conditions:
I want a zoomed-in version of the figure. In other words, a part of data points of some time range (e.g., 2~3 hours) is shown at once. Then, there should be enough space between adjacent points.
I want save the figure as png or pdf file. Then, if I open the file, the image (or pdf) viewer has a horizontal scroll bar which enables me to explore the whole figure.
Is there anyone who can solve it?
I do not think it will be not hard for a matplotlib expert, but quite hard for me, a beginner.
note to readers: answer changed significantly from v1 due to clarification of the question
I want a zoomed-in version of the figure. In other words, a part of data points of some time range (e.g., 2~3 hours) is shown at once. Then, there should be enough space between adjacent points.
Zooming in matplotlib is implemented with the x and y limits of the axis. So you can simply change the arguments to your call to ax.set_xlim such that the corresponding times differ by 2-3 hours or however long you want. Knowing that you have a sample every 5 minutes, since 2 hours/(5 min/sample) = 24, you could use
ax.set_xlim(ts.index.min(),ts.index.min() + 24)
to get a 2-hour range.
I want save the figure as png or pdf file. Then, if I open the file, the image (or pdf) viewer has a horizontal scroll bar which enables me to explore the whole figure.
Use savefig to save the figure to a file. Note that if you have set the axis limits using set_xlim or xlim or equivalent, this will save only the portion of the figure that is visible within the given limits. So to save the entire figure (with all data points visible), you will need to set the axis limits to the minimum and maximum values, respectively.
When you open the image/PDF file in a viewer, whether it displays a scroll bar (and how much of the figure is shown) is entirely up to the viewer. You cannot control this in Python. But you can give it some chance of showing up with a horizontal scroll bar by making the figure very large in the horizontal direction. To do so, you can pass the figsize=(width, height) keyword argument when creating the figure, or use the set_size_inches(width, height) method on an existing Figure object. The measurements are in inches in both cases. Pass a value for width that is much larger than that for height and you will get a very wide figure; for example, 40 for width and 4 for height. You'll have to experiment with these values to find which ones give your figure the proportions you want.

Categories

Resources