matplotlib / matplotlib/ipympl
Exporting/Printing always saves to low-res PNG; device_pixel_ratio doesn't seem to be set correctly
Chưa có ai nhận issue này.
- Ngôn ngữ chính
- Jupyter Notebook
- Star
- 1.7k
- Fork
- 234
- Chỉ số merge pull request
- Không có pull request nào được merge trong 30 ngày
Mô tả
Describe the issue
If I'm using %matplotlib widget, and then I try to print, export, etc, it always prints to a low-res PNG. Inspection of the notebook reveals that ipympl stores a low-res PNG alongside the reference to the interactive widget, and then (naively) scales it based on the DPI. I can set the DPI via the figure
The culprit seems to be around line 327 of backend_nbagg.py:
def _repr_mimebundle_(self, **kwargs):
# now happens before the actual display call.
if hasattr(self, '_handle_displayed'):
self._handle_displayed(**kwargs)
plaintext = repr(self)
if len(plaintext) > 110:
plaintext = plaintext[:110] + '…'
buf = io.BytesIO()
self.figure.savefig(buf, format='png', dpi='figure')
base64_image = b64encode(buf.getvalue()).decode('utf-8')
self._data_url = f'data:image/png;base64,{base64_image}'
# Figure size in pixels
pwidth = self.figure.get_figwidth() * self.figure.get_dpi()
pheight = self.figure.get_figheight() * self.figure.get_dpi()
# Scale size to match widget on HiDPI monitors.
if hasattr(self, 'device_pixel_ratio'): # Matplotlib 3.5+
width = pwidth / self.device_pixel_ratio
height = pheight / self.device_pixel_ratio
else:
width = pwidth / self._dpi_ratio
height = pheight / self._dpi_ratio
html = """
<div style="display: inline-block;">
<div class="jupyter-widgets widget-label" style="text-align: center;">
{}
</div>
<img src='{}' width={} dpi={} dpi-ratio={}/>
</div>
""".format(
self._figure_label, self._data_url, width, self.figure.get_dpi(), self.device_pixel_ratio
)
# Update the widget model properly for HTML embedding
self._size = (width, height)
data = {
'text/plain': plaintext,
'image/png': base64_image,
'text/html': html,
'application/vnd.jupyter.widget-view+json': {
'version_major': 2,
'version_minor': 0,
'model_id': self._model_id,
},
}
return data
Note that I've added a bit of debugging here:
html = """
<div style="display: inline-block;">
<div class="jupyter-widgets widget-label" style="text-align: center;">
{}
</div>
<img src='{}' width={} dpi={} dpi-ratio={}/>
</div>
""".format(
self._figure_label, self._data_url, width, self.figure.get_dpi(), self.device_pixel_ratio
so that it outputs the dpi and pixel ratio as well. For whatever reason, the dpi-ratio is set to 1, even though I'm on a Retina screen where it should be 2:
Python 3.11.9 | packaged by conda-forge | (main, Apr 19 2024, 18:34:54) [Clang 16.0.6 ] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import matplotlib.pyplot as plt
>>> fig = plt.figure()
>>> fig.canvas.device_pixel_ratio
2.0
The dpi is set to 100. These two things partly cancel out, so that I end up getting a low-res image, but we aren't dividing the pwidth by 2 (as it thinks the pixel ratio is 1). The result is a pixelated, upscaled, low-res image.
In short, I'm not sure where it's getting the pixel ratio from, but it doesn't seem to be getting set correctly on my system. I've tried this both in JupyterLab and VSCode.
Versions
$ python -c "import sys; print('\n',sys.version); import ipympl; print('ipympl version:', ipympl.__version__)" && jupyter --version && jupyter nbextension list && jupyter labextension list
3.11.9 | packaged by conda-forge | (main, Apr 19 2024, 18:34:54) [Clang 16.0.6 ]
ipympl version: 0.9.4
Selected Jupyter core packages...
IPython : 8.17.2
ipykernel : 6.29.4
ipywidgets : 8.1.3
jupyter_client : 8.6.2
jupyter_core : 5.7.2
jupyter_server : 2.14.1
jupyterlab : 4.2.2
nbclient : 0.10.0
nbconvert : 7.16.4
nbformat : 5.10.4
notebook : 7.2.1
qtconsole : 5.5.2
traitlets : 5.14.3
usage: jupyter [-h] [--version] [--config-dir] [--data-dir] [--runtime-dir] [--paths] [--json] [--debug] [subcommand]
Jupyter: Interactive Computing
positional arguments:
subcommand the subcommand to launch
options:
-h, --help show this help message and exit
--version show the versions of core jupyter packages and exit
--config-dir show Jupyter config dir
--data-dir show Jupyter data dir
--runtime-dir show Jupyter runtime dir
--paths show all Jupyter paths. Add --json for machine-readable format.
--json output paths as machine-readable json
--debug output debug information about paths
Available subcommands: console dejavu events execute kernel kernelspec lab labextension labhub migrate nbclassic nbconvert notebook qtconsole run server
troubleshoot trust
Jupyter command `jupyter-nbextension` not found.
Hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Hướng nghiên cứu
Bắt đầu với backend_nbagg.py, tại khu vực quanh repr_mimebundle, và tái hiện vấn đề bằng cách sử dụng %matplotlib widget trên màn hình Retina trong JupyterLab hoặc VSCode. Theo dõi cách device_pixel_ratio đi đến phần biểu diễn HTML và widget, rồi so sánh với fig.canvas.device_pixel_ratio. Hoàn thành khi các hình được xuất hoặc in giữ lại số pixel độ phân giải cao như mong đợi, thay vì bị phóng to từ một PNG độ phân giải thấp.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- jupyter-notebook, python
- Lĩnh vực
- backend, frontend
- Loại issue
- Lỗi
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức độ hoạt động
- Đình trệ
- Độ rõ ràng
- Khá rõ ràng
- Mức phù hợp với người mới
- 42/100