Coder Social home page Coder Social logo

rougier / scientific-visualization-book Goto Github PK

View Code? Open in Web Editor NEW
10.1K 187.0 962.0 389.07 MB

An open access book on scientific visualization using python and matplotlib

Home Page: https://www.labri.fr/perso/nrougier/

License: Other

Makefile 1.13% Python 91.94% TeX 6.64% Shell 0.28%
python matplotlib dataviz scientific-publications book open-access numpy plotting

scientific-visualization-book's Introduction

Scientific Visualization: Python + Matplotlib

Nicolas P. Rougier, Bordeaux, November 2021.

Front cover

The Python scientific visualisation landscape is huge. It is composed of a myriad of tools, ranging from the most versatile and widely used down to the more specialised and confidential. Some of these tools are community based while others are developed by companies. Some are made specifically for the web, others are for the desktop only, some deal with 3D and large data, while others target flawless 2D rendering. In this landscape, Matplotlib has a very special place. It is a versatile and powerful library that allows you to design very high quality figures, suitable for scientific publishing. It also offers a simple and intuitive interface as well as an object oriented architecture that allows you to tweak anything within a figure. Finally, it can be used as a regular graphic library in order to design non‐scientific figures. This book is organized into four parts. The first part considers the fundamental principles of the Matplotlib library. This includes reviewing the different parts that constitute a figure, the different coordinate systems, the available scales and projections, and we’ll also introduce a few concepts related to typography and colors. The second part is dedicated to the actual design of a figure. After introducing some simple rules for generating better figures, we’ll then go on to explain the Matplotlib defaults and styling system before diving on into figure layout organization. We’ll then explore the different types of plot available and see how a figure can be ornamented with different elements. The third part is dedicated to more advanced concepts, namely 3D figures, optimization & animation. The fourth and final part is a collection of showcases.

Read the book

You can read the book PDF (95Mo, preferred site) that is open access and hosted on HAL which is a French open archive for academics. Up to date version is also available on GitHub here. Sources for the book (including code examples) are available at github.com/rougier/scientific-visualization-book.

Buy the book

If you want to buy the book, you can order a printed edition at amazon.com for 49$. If you want to support or sponsor my future work on Python (and Emacs), you can use paypal, github or liberapay.

If you don't want to spend money, you can simply nominate me for the GitHub stars program if you find my work useful for the community.

Build the book

Ubuntu

See also

Book gallery

scientific-visualization-book's People

Contributors

alohr avatar emmetz avatar fmassin avatar fsoubelet avatar guillermoaguilar avatar iamsaswata avatar jcgoran avatar jehyunlee avatar juba avatar kinow avatar labdmitriy avatar leejjoon avatar mzl9039 avatar nicolanrizzo avatar rougier avatar sdoro avatar singularitti avatar smartlixx avatar stfpz avatar toshiakiasakura avatar whrvt avatar wwliao avatar xxyzz avatar zhangkaihua88 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

scientific-visualization-book's Issues

Transparency example (fig 12.1) not showing properly in pdf

In figure 12.1 on page 149, the rightmost 3 markers are shown as white in the pdf.
When I run the script and save as .pdf the same happens, but when I save that figure as .png the markers are shades of grey (as expected).

Might just be a bug in matplotlib, since one would expect that saving as .pdf produces the same image as saving as .png. Besides the fact that one is vector based and the other is raster based.

Error in text-polar.py

Thank you for the excellent book.

I am getting errors in the text-polar.py from the chapter scales-projections.

The error is:

ValueError Traceback (most recent call last)
Input In [804], in
57 ax.add_artist(patch)
60 # This could be made through a list but it is easier to red this way
---> 61 label("JANUARY", 0.5 * 2 * np.pi / 12, 1 - 0.5 * size)
62 label("FEBRUARY", 1.5 * 2 * np.pi / 12, 1 - 0.5 * size)
63 label("MARCH", 2.5 * 2 * np.pi / 12, 1 - 0.5 * size)

Input In [804], in label(text, angle, radius, scale)
48 xmin, xmax = V[:, 0].min(), V[:, 0].max()
49 ymin, ymax = V[:, 1].min(), V[:, 1].max()
---> 50 V -= (xmin + xmax) / 2, (ymin + ymax) / 2
51 V *= scale
52 for i in range(len(V)):

ValueError: output array is read-only

I am using numpy version 1.22.0 and matplotlib version 3.5.1

Inconsistent commas in the code (Chapter 2, page 22)

Hi @rougier,

Еhere is a slight inconsistency in the code from the book - there is no comma after zorder argument, but after linestyle argument there is a comma (technically the latter case is not an error, but usually trailing comma is used with different code formatting):

plt.plot(P[:,0], P[:,1], clip_on=False, zorder=-10
         color="k", linewidth=1.0, linestyle="--", )

Perhaps the following code was meant:

plt.plot(P[:,0], P[:,1], clip_on=False, zorder=-10,
         color="k", linewidth=1.0, linestyle="--")

Thank you.

News

Setup the private repo and clean it up before pushing to GitHub.

Image licensing

I'd like to start by deeply thanking you @rougier. This book is wonderful, and I thoroughly enjoyed reading it, as I enjoyed reading the NumPy book and investigating the NumPy exercises :)

To my question now: are the figures free to reuse in a commercial setting? I ask because the code of the figures seems to be (BSD) but the book is not (CC-BY-SA-NC). I ask because I'd like to include some of the book figures in some slides I have for a professional training session on matplotlib.

Thanks again for your great work and commitment to open source!

Height parameter of the "Floating & rotated axis" in Figure 2.9

Hi, thanks for your excellent book!

It seems to me that the 50th line of coordinates/transforms‐floating‐axis.py, as well as the corresponding line of the code in rst/coordinates.rst,
ax2.set_position((xmin, ymin, xmax - xmin, ymax - xmin))
should read
ax2.set_position((xmin, ymin, xmax - xmin, ymax - ymin)),
although the difference between ymax-xmin=0.40836979896182274 and ymax-ymin=0.38490475395717544 happens to be small and not apparent in the figure...

By the way, in the official document of Matplotlib there seems to be no description of FloatingAxesHostAxes, of which FloatingSubplot is an alias; I'd be glad if you kindly lead me to it...

Thanks,
Kazuyoshi

The collage example at page 25 with some images doesn't work

The first function instruction of imshow has a problem because the length t-uple ranges between 2 and 3.
We have resolved the problem by replacing the line:

height, width = I.shape

with:

height, width = I.shape[0], I.shape[1]

bye

ps. What a great book! :-)

BUG: showcase textspiral, assignment destination is read-only

I try to replicate shocase/text-spiral.py in my laptop.

I tried to run the following code.

import mpmath

mpmath.mp.dps = 15000
text = str(mpmath.pi)

path = TextPath((0, 0), text, size=6, ) #, prop=FontProperties(family="Source Serif Pro"))
#path.vertices.setflags(write=1)
Vx, Vy = path.vertices[:, 0], path.vertices[:, 1]
X = np.interp(Vx, L, T[:, 0]) + Vy * np.interp(Vx, L, O[:, 0])
Y = np.interp(Vx, L, T[:, 1]) + Vy * np.interp(Vx, L, O[:, 1])
Vx[...] = X
Vy[...] = Y

Then I encountered ValueError: assignment destination is read-only.
If I add the line path.vertices.setflags(write=1) right after path object is created,
I can reproduce the showcase.

I used matplotlib 3.6.3, which might be different behaviour for a default object editing permission (can be checked by path.vertices.flags) .

Hope this comment will help improve reproducibility.

Wrong Code in page 96 (Size, aspect & layout)?

When I run the code F, H and I scripts in Page 96 (Chapter 8 Size, aspect & layout), I got the figure as shown in the following figures. It is different from Figure 8.1. When I modify the axes aspect to 0.5, 1 and 2 respectively, it gets normal. It seems that aspect='auto' doesn't work.

  • F, H and I
    F script
    H script
    I script

Marker code of the 'scatter-3D' example

Thanks for your book! The figures are amazing.
Since I am working in 3D and have to play around with point clouds a lot, I really want to know how the 'Scatter-3D' exmaple is made.
It seems the core part is the custom marker. The marker's fading shadow rings create a beautiful effect of 3D shading.
Can you share the code for creating this example? Thanks a lot!

scatter-3d 1

Different licensing for the code

First of all, this looks amazing! 👏

Would you consider making the code available using another license than a creative common?

The reason is that, as with StackOverflow, CC is not compatible with licenses like MIT and BSD.

Maybe typo in showcase ? (missing "of"?)

\nicefrac{1}{z}` in the domain :math:`[-2.5, 2.5]^2`. I used the angle
of the (complex) result for setting the color and the absolute cosine
the norm for modulating it periodically. I could have used a cyclic

\nicefrac{1}{z}` in the domain :math:`[-2.5, 2.5]^2`. I used the angle
of the (complex) result for setting the color and the absolute cosine
the norm for modulating it periodically.

"the absolute cosine the norm" seem like a typo to me. It's likely the absolute cosine of the norm? As the code roughly does abs(cos(abs(N)) modulo constants.

Otherwise this looks fantastic ! I'm going to try to convince some folks to get it for their grad students bookshelves.

Requirements files for package versions

Having the versions of packages used for the book in a requirements.txt would be helpful for others reproducing things a year or so down the line.

Looking through the repo for something such as numpy doesn't bring up anything wrt the version used, just that it's imported in several locations.

As this book was only recently finished, perhaps there's an environment on the authors computer which has all the correct package versions within it? And a file could be generated from that.

Example search for numpy with rg numpy :

README.md:* [From Python to Numpy](https://www.labri.fr/perso/nrougier/from-python-to-numpy/) (Scientific Python Volume I)
README.md:* [100 Numpy exercices](https://github.com/rougier/numpy-100)
rst/threed.rst:specify the color of each of the triangle using a numpy array, so let's just do
rst/anatomy.rst:   import numpy as np
rst/anatomy.rst:   import numpy as np
rst/00-preface.rst:   import numpy as np
rst/00-preface.rst:   >>> import numpy; print(numpy.__version__)
code/showcases/escher-movie.py:import numpy as np
code/showcases/domain-coloring.py:import numpy as np
code/showcases/mandelbrot.py:import numpy as np
code/showcases/text-shadow.py:import numpy as np
code/showcases/windmap.py:import numpy as np
code/showcases/mosaic.py:import numpy as np
code/showcases/mosaic.py:        from numpy.random.mtrand import RandomState
code/showcases/contour-dropshadow.py:import numpy as np
code/showcases/escher.py:import numpy as np
code/showcases/text-spiral.py:import numpy as np
code/showcases/recursive-voronoi.py:import numpy as np
code/showcases/recursive-voronoi.py:        from numpy.random.mtrand import RandomState
code/showcases/waterfall-3d.py:import numpy as np
rst/defaults.rst:   import numpy as np
code/beyond/stamp.py:import numpy as np
code/beyond/dyson-hatching.py:import numpy as np
code/beyond/tikz-dashes.py:import numpy as np
rst/coordinates.rst:   import numpy as np
rst/animation.rst:   import numpy as np
rst/animation.rst:   import numpy as np
rst/animation.rst:   import numpy as np
code/beyond/tinybot.py:import numpy as np
code/beyond/dungeon.py:import numpy as np
cover/cover-pattern.py:import numpy as np
code/beyond/interactive-loupe.py:import numpy as np
code/beyond/bluenoise.py:import numpy as np
code/beyond/bluenoise.py:        from numpy.random.mtrand import RandomState
code/beyond/polygon-clipping.py:import numpy as np
code/beyond/radial-maze.py:import numpy as np
code/reference/hatch.py:import numpy as np
code/reference/colormap-sequential-1.py:import numpy as np
code/reference/colormap-uniform.py:import numpy as np
code/reference/marker.py:import numpy as np
code/reference/line.py:import numpy as np
code/ornaments/annotation-zoom.py:import numpy as np
code/scales-projections/text-polar.py:import numpy as np
code/ornaments/legend-regular.py:import numpy as np
code/ornaments/elegant-scatter.py:import numpy as np
code/reference/axes-adjustment.py:import numpy as np
code/ornaments/legend-alternatives.py:import numpy as np
code/reference/colorspec.py:import numpy as np
code/typography/typography-matters.py:import numpy as np
code/colors/color-gradients.py:import numpy as np
code/threed/bunny-6.py:import numpy as np
code/scales-projections/projection-polar-config.py:import numpy as np
code/colors/color-wheel.py:import numpy as np
code/colors/mona-lisa.py:import numpy as np
code/threed/bunny-4.py:import numpy as np
code/ornaments/title-regular.py:import numpy as np
code/typography/text-outline.py:import numpy as np
code/ornaments/bessel-functions.py:import numpy as np
code/scales-projections/projection-polar-histogram.py:import numpy as np
code/rules/rule-6.py:import numpy as np
code/colors/open-colors.py:import numpy as np
code/colors/material-colors.py:import numpy as np
code/colors/flower-polar.py:import numpy as np
code/typography/typography-legibility.py:import numpy as np
code/colors/colored-plot.py:import numpy as np
code/rules/rule-7.py:import numpy as np
code/colors/colored-hist.py:import numpy as np
code/rules/rule-3.py:import numpy as np
code/colors/alpha-vs-color.py:import numpy as np
code/colors/stacked-plots.py:import numpy as np
code/ornaments/label-alternatives.py:import numpy as np
code/typography/tick-labels-variation.py:import numpy as np
code/rules/projections.py:import numpy as np
code/typography/typography-math-stacks.py:import numpy as np
code/rules/rule-2.py:import numpy as np
code/colors/alpha-scatter.py:import numpy as np
code/typography/typography-text-path.py:import numpy as np
code/scales-projections/polar-patterns.py:import numpy as np
code/scales-projections/scales-custom.py:import numpy as np
code/rules/parameters.py:import numpy as np
code/threed/bunny-1.py:import numpy as np
code/scales-projections/geo-projections.py:import numpy as np
code/rules/rule-8.py:import numpy as np
code/threed/bunny-5.py:import numpy as np
code/ornaments/latex-text-box.py:import numpy as np
code/ornaments/annotation-direct.py:import numpy as np
code/typography/projection-3d-gaussian.py:import numpy as np
code/threed/bunny-7.py:import numpy as np
code/rules/helper.py:import numpy as np
code/rules/helper.py:    """ Generate a numpy array containing a disc. """
code/typography/typography-font-stacks.py:import numpy as np
code/scales-projections/scales-log-log.py:import numpy as np
code/scales-projections/projection-3d-frame.py:import numpy as np
code/threed/bunnies.py:import numpy as np
code/threed/bunny.py:import numpy as np
code/threed/bunny-3.py:import numpy as np
code/rules/rule-9.py:import numpy as np
code/ornaments/annotate-regular.py:import numpy as np
code/threed/bunny-2.py:import numpy as np
code/reference/tick-locator.py:import numpy as np
code/threed/bunny-8.py:import numpy as np
code/reference/colormap-diverging.py:import numpy as np
code/scales-projections/scales-comparison.py:import numpy as np
code/reference/text-alignment.py:import numpy as np
code/scales-projections/scales-check.py:import numpy as np
code/reference/scale.py:import numpy as np
code/reference/colormap-qualitative.py:import numpy as np
code/reference/tick-formatter.py:import numpy as np
code/rules/graphics.py:import numpy as np
code/rules/rule-1.py:import numpy as np
code/reference/collection.py:import numpy as np
code/ornaments/annotation-side.py:import numpy as np
code/reference/colormap-sequential-2.py:import numpy as np
code/defaults/defaults-exercice-1.py:import numpy as np
code/animation/platecarree.py:import numpy as np
code/defaults/defaults-step-4.py:import numpy as np
code/layout/standard-layout-2.py:import numpy as np
code/coordinates/transforms-blend.py:import numpy as np
code/unsorted/layout-weird.py:import numpy as np
code/unsorted/advanced-linestyles.py:import numpy as np
code/coordinates/transforms-exercise-1.py:import numpy as np
code/animation/fluid-animation.py:import numpy as np
code/unsorted/alpha-gradient.py:import numpy as np
code/animation/sine-cosine.py:import numpy as np
code/optimization/line-benchmark.py:import numpy as np
code/animation/fluid.py:import numpy as np
code/optimization/transparency.py:import numpy as np
code/animation/rain.py:import numpy as np
code/optimization/scatter-benchmark.py:import numpy as np
code/optimization/self-cover.py:import numpy as np
code/animation/imgcat.py:import numpy as np
code/unsorted/hatched-bars.py:import numpy as np
code/optimization/multithread.py:import numpy as np
code/animation/earthquakes.py:import numpy as np
code/unsorted/poster-layout.py:import numpy as np
code/coordinates/transforms-letter.py:import numpy as np
code/optimization/scatters.py:import numpy as np
code/animation/sine-cosine-mp4.py:import numpy as np
code/optimization/multisample.py:import numpy as np
code/unsorted/make-hatch-linewidth.py:import numpy as np
code/animation/lissajous.py:import numpy as np
code/coordinates/transforms-polar.py:import numpy as np
code/unsorted/earthquakes.py:import numpy as np
code/unsorted/git-commits.py:import numpy as np
code/unsorted/github-activity.py:import numpy as np
code/coordinates/collage.py:import numpy as np
code/introduction/matplotlib-timeline.py:import numpy as np
code/coordinates/transforms-floating-axis.py:import numpy as np
code/coordinates/transforms-hist.py:import numpy as np
code/layout/complex-layout-bare.py:import numpy as np
code/animation/less-is-more.py:import numpy as np
code/coordinates/transforms.py:import numpy as np
code/unsorted/alpha-compositing.py:import numpy as np
code/layout/standard-layout-1.py:import numpy as np
code/layout/layout-classical.py:import numpy as np
code/unsorted/stacked-bars.py:import numpy as np
code/layout/complex-layout.py:import numpy as np
code/layout/layout-aspect.py:import numpy as np
code/unsorted/metropolis.py:import numpy as np
code/unsorted/scale-logit.py:import numpy as np
code/unsorted/dyson-hatching.py:import numpy as np
code/unsorted/dyson-hatching.py:        from numpy.random.mtrand import RandomState
code/layout/layout-gridspec.py:import numpy as np
code/defaults/defaults-step-1.py:import numpy as np
code/defaults/defaults-step-2.py:import numpy as np
code/defaults/defaults-step-5.py:import numpy as np
code/defaults/defaults-step-3.py:import numpy as np
code/anatomy/bold-ticklabel.py:import numpy as np
code/unsorted/3d/contour.py:import numpy as np
code/unsorted/3d/sphere.py:import numpy as np
code/unsorted/3d/platonic-solids.py:import numpy as np
code/unsorted/3d/surf.py:import numpy as np
code/unsorted/3d/bar.py:import numpy as np
tex/cover-pattern.py:import numpy as np
code/unsorted/3d/scatter.py:import numpy as np
tex/book.bib:  url =          {https://www.labri.fr/perso/nrougier/from-python-to-numpy/},
code/anatomy/pixel-font.py:import numpy as np
code/anatomy/raster-vector.py:import numpy as np
code/anatomy/zorder-plots.py:import numpy as np
code/anatomy/ruler.py:import numpy as np
code/anatomy/anatomy.py:import numpy as np
code/anatomy/zorder.py:import numpy as np
code/unsorted/3d/bunny.py:import numpy as np
code/unsorted/3d/bunnies.py:import numpy as np
code/unsorted/3d/plot.py:import numpy as np
code/unsorted/3d/plot.py:    camera : 4x4 numpy array
code/unsorted/3d/glm.py:import numpy as np

These seem to be the imports used in the text:

 'from __future__ import absolute_import',
 'from __future__ import division',
 'from __future__ import print_function',
 'from __future__ import unicode_literals',
 'from datetime import date, datetime',
 'from datetime import datetime',
 'from dateutil.relativedelta import relativedelta',
 'from docutils import nodes',
 'from docutils.core import publish_cmdline',
 'from docutils.parsers.rst import directives, Directive',
 'from fluid import Fluid, inflow',
 'from functools import reduce',
 'from graphics import *',
 'from helper import *',
 'from itertools import cycle',
 'from math import cos, sin, floor, sqrt, pi, ceil',
 'from math import factorial',
 'from math import sqrt, ceil, floor, pi, cos, sin',
 'from matplotlib import colors',
 'from matplotlib import ticker',
 'from matplotlib.animation import FuncAnimation, writers',
 'from matplotlib.artist import Artist',
 'from matplotlib.backend_bases import GraphicsContextBase, RendererBase',
 'from matplotlib.backends.backend_agg import FigureCanvas',
 'from matplotlib.backends.backend_agg import FigureCanvasAgg',
 'from matplotlib.collections import AsteriskPolygonCollection',
 'from matplotlib.collections import CircleCollection',
 'from matplotlib.collections import EllipseCollection',
 'from matplotlib.collections import LineCollection',
 'from matplotlib.collections import PatchCollection',
 'from matplotlib.collections import PathCollection',
 'from matplotlib.collections import PolyCollection',
 'from matplotlib.collections import PolyCollection',
 'from matplotlib.collections import QuadMesh',
 'from matplotlib.collections import RegularPolyCollection',
 'from matplotlib.collections import StarPolygonCollection',
 'from matplotlib.colors import LightSource',
 'from matplotlib.figure import Figure',
 'from matplotlib.font_manager import FontProperties',
 'from matplotlib.font_manager import findfont, FontProperties',
 'from matplotlib.gridspec import GridSpec',
 'from matplotlib.gridspec import GridSpec',
 'from matplotlib.patches import Circle',
 'from matplotlib.patches import Circle',
 'from matplotlib.patches import Circle, Rectangle',
 'from matplotlib.patches import ConnectionPatch',
 'from matplotlib.patches import Ellipse',
 'from matplotlib.patches import Ellipse',
 'from matplotlib.patches import FancyBboxPatch',
 'from matplotlib.patches import PathPatch',
 'from matplotlib.patches import Polygon',
 'from matplotlib.patches import Polygon',
 'from matplotlib.patches import Polygon, Ellipse',
 'from matplotlib.patches import Rectangle',
 'from matplotlib.patches import Rectangle, PathPatch',
 'from matplotlib.path import Path',
 'from matplotlib.patheffects import Stroke, Normal',
 'from matplotlib.patheffects import withStroke',
 'from matplotlib.text import TextPath',
 'from matplotlib.textpath import TextPath',
 'from matplotlib.ticker import AutoMinorLocator, MultipleLocator, FuncFormatter',
 'from matplotlib.ticker import MultipleLocator',
 'from matplotlib.ticker import NullFormatter',
 'from matplotlib.ticker import NullFormatter, MultipleLocator',
 'from matplotlib.ticker import NullFormatter, SymmetricalLogLocator',
 'from matplotlib.transforms import Affine2D',
 'from matplotlib.transforms import ScaledTranslation',
 'from matplotlib.transforms import blended_transform_factory, ScaledTranslation',
 'from mpl_toolkits.axes_grid1 import ImageGrid',
 'from mpl_toolkits.axes_grid1 import ImageGrid',
 'from mpl_toolkits.axes_grid1 import make_axes_locatable',
 'from mpl_toolkits.axes_grid1.inset_locator import inset_axes',
 'from mpl_toolkits.axes_grid1.inset_locator import mark_inset',
 'from mpl_toolkits.axes_grid1.inset_locator import mark_inset',
 'from mpl_toolkits.axes_grid1.inset_locator import zoomed_inset_axes',
 'from mpl_toolkits.axes_grid1.inset_locator import zoomed_inset_axes',
 'from mpl_toolkits.mplot3d import Axes3D, art3d',
 'from mpl_toolkits.mplot3d import Axes3D, proj3d, art3d',
 'from multiprocessing import Pool',
 'from numpy.random.mtrand import RandomState',
 'from parameters import *',
 'from pathlib import Path',
 'from projections import *',
 'from pylab import *',
 'from scipy.ndimage import gaussian_filter',
 'from scipy.ndimage import gaussian_filter1d',
 'from scipy.ndimage import map_coordinates, spline_filter',
 'from scipy.sparse.linalg import factorized',
 'from scipy.spatial import Voronoi',
 'from scipy.special import erf',
 'from scipy.special import jn, jn_zeros',
 'from shapely.geometry import Polygon',
 'from shapely.geometry import box, Polygon',
 'from skimage.color import rgb2lab, lab2rgb, rgb2xyz, xyz2rgb',
 'from timeit import default_timer as timer',
 'from tqdm.autonotebook import tqdm',
 'import bluenoise',
 'import cartopy',
 'import cartopy.crs',
 'import cartopy.crs as ccrs',
 'import colorsys',
 'import dateutil.parser',
 'import git',
 'import glm',
 'import html.parser',
 'import imageio',
 'import locale',
 'import math',
 'import matplotlib',
 'import matplotlib as mpl',
 'import matplotlib.animation as animation',
 'import matplotlib.animation as animation',
 'import matplotlib.colors as colors',
 'import matplotlib.colors as mc',
 'import matplotlib.colors as mcolors',
 'import matplotlib.gridspec as gridspec',
 'import matplotlib.image as mpimg',
 'import matplotlib.patches as mpatch',
 'import matplotlib.patches as mpatches',
 'import matplotlib.patches as patches',
 'import matplotlib.path as mpath',
 'import matplotlib.path as path',
 'import matplotlib.patheffects as PathEffects',
 'import matplotlib.patheffects as path_effects',
 'import matplotlib.pylab as plt',
 'import matplotlib.pyplot as plt',
 'import matplotlib.pyplot as plt',
 'import matplotlib.ticker as ticker',
 'import matplotlib.transforms as transforms',
 'import mpl_toolkits.axisartist.floating_axes as floating_axes',
 'import mpl_toolkits.mplot3d.art3d as art3d',
 'import mpmath',
 'import noise',
 'import numpy as np',
 'import os',
 'import plot',
 'import re',
 'import scipy',
 'import scipy.sparse as sp',
 'import scipy.spatial',
 'import shapely.geometry',
 'import sys',
 'import tqdm',
 'import tqdm',
 'import types',
 'import urllib',
 'import urllib.request'

"text positioning with transforms" example (figure 2.4) should perhaps normalize dx, dy by 72, not by fig.dpi

The code for figure 2.4 is reproduced below for convenience:

from matplotlib.transforms import ScaleTranslation

fig = plt.figure(figsize=(6, 4))

ax = fig.add_subplot(2, 1, 1)
plt.text(0.1, 0.1, "A", transform=ax.transAxes)

ax = fig.add_subplot(2, 1, 2)
dx, dy = 10/fig.dpi, 10/fig.dpi
offset = ScaledTranslation(dx, dy, fig.dpi_scale_trans)
plt.text(0, 0, "B", transform=ax.transAxes + offset)

plt.show()

I believe the scaling of dx, dy should be a division by 72, not by fig.dpi (more or less as you do in figure 2.5, in fact), as otherwise the appearance of the figure will depend on figure.dpi; e.g.

from matplotlib import pyplot as plt, transforms as tr

size = 10

for dpi in [72, 300]:
    fig = plt.figure(dpi=dpi)

    ax = fig.add_subplot(2, 1, 1)
    dx = dy = size / fig.dpi
    offset = tr.ScaledTranslation(dx, dy, fig.dpi_scale_trans)
    ax.text(0, 0, "A", transform=ax.transAxes + offset, size=size)

    ax = fig.add_subplot(2, 1, 2)
    dx = dy = size / 72
    offset = tr.ScaledTranslation(dx, dy, fig.dpi_scale_trans)
    ax.text(0, 0, "A", transform=ax.transAxes + offset, size=size)

    fig.savefig(f"/tmp/test{dpi}.png")
    fig.savefig(f"/tmp/test{dpi}.pdf")

You can verify that here, the visual appearance of the top axis changes whereas the bottom one doesn't.

In a sense, this is redundant with figure 2.5; but perhaps division-by-72 should really be mentioned first and division-by-fig.dpi is more a side possibility?

Subplot margins (Chapter 1, Exercise 2)

Hi @rougier,

There is a statement about additional figure margins for Exercise 2 solution:

# However, we need to have margins in our figure (or tick labels will be cut)
# so we'll have 0.25 inches margin on each side of the axis such that the axis
# will be 4 inches.

And there is a code that performs this adjustment:
inch = 2.54
fig_width = 10.8 / inch # ~4.252 inches
fig_height = 1.25 # 1.250 inches
margin = 0.125 # 0.125 inches
fig = plt.figure(figsize=(fig_width, fig_height))
plt.subplots_adjust(
left=0.5 * margin / fig_width,
right=1 - 0.5 * margin / fig_width,
bottom=0.5 * margin / fig_height,
top=1 - 0.5 * margin / fig_height,
)

It seems that in this case we need to have 0.125 inches margin on each side (not 0.25 as in the description), and margin=0.25 (not 0.125 as in the code) because we multiply this margin by 0.5 when we call plt.subplots_adjust().
Is it correct?

Thank you.

Code for Figure 2.3 from the book doesn't match the image (Chapter 2, pages 22-23)

Hi @rougier,

If we use the code for the Figure 2.3 from the book, then the border will be inside data coordinates, not outside as expected, and with different tick labels (specifying the code from the book before resolving #63):

fig = plt.figure(figsize=(5, 5), dpi=100)
ax = fig.add_subplot(1, 1, 1, projection='polar')

FC_to_DC = ax.transData.inverted().transform
NDC_to_FC = ax.transAxes.transform
NDC_to_DC = lambda x: FC_to_DC(NDC_to_FC(x))

P = NDC_to_DC([[0,0], [1,0], [1,1], [0,1], [0,0]])

plt.plot(P[:,0], P[:,1], clip_on=False, zorder=-10
         color="k", linewidth=1.0, linestyle="--", )
plt.scatter(P[:-1,0], P[:-1,1],
            clip_on=False, facecolor="w", edgecolor="k")
plt.show()

But the code in Python file is correct.
I compared the code and find that for displaying the figure there are 2 additional lines in Python file:

ax.set_ylim(-1, 1), ax.set_yticks([-1, -0.5, 0, 0.5, 1])

And the first line (setting the limits for y-axis and specifying tick labels) is required to get expected figure.

Thank you.

Typo found

where your data will be rendered. It is also called a subplot. You can have
have one to many axes per figure and each is usually surrounded by four edges

There are two "have" in:

"You can have have one to many axes per figure and each is usually surrounded by four edges (left, top, right and bottom) that are called spines. "

Congrats on the first public release and thank you for spending time on this book! ❤️

Minor typo on page 177

This sentence "Filled contours with dropshadows is a nice effet that allows" has effect misspelled.

Wrong code and spelling

hi, thanks for your work on this awesome book! I just start reading and it helps me much on understanding matplotlib!

by the way, i found a mistake on Scales & projections

It is the code below:

   >>> fig = plt.figure(figsize=(6,6))
   >>> ax = plt.subplot(1, 1, 1,
                        aspect=1, xlim=[0,100], ylim=[0,100])
   >>> P0, P1, P2, P3 = (0.1, 0.1), (1,1), (10,10), (100,100)
   >>> transform = ax.transData.transform
   >>> print( (transform(P1)-transform(P0))[0] )
   4.185
   >>> print( (transform(P2)-transform(P1))[0] )
   41.85
   >>> print( (transform(P1)-transform(P0))[0] )
   418.5

the last one should be:

print( (transform(P3)-transform(P2))[0] )

same issues occurred both on checking "linear scale" and "log scale"

Incorrect description and links to the code for Figures 2.3-2.5 (Chapter 2, pages 23-25)

Hi @rougier,

The links to the code for Figures 2.3-2.5 have the name coordinates/transform‐*.py and URL https://github.com/rougier/scientific-visualization-book/blob/master/code/coordinates/transform-*.py, but the files have the name transforms-*.py, so probably the following will be correct:
Name - coordinates/transforms‐*.py
URL - https://github.com/rougier/scientific-visualization-book/blob/master/code/coordinates/transforms-*.py

Also for Figure 2.5 there is the same description as for Figure 2.3 (except for file name):

Figure 2.3
Axes boundaries in polar projection using a transform from normalized data co‐
ordinates to data coordinates (coordinates/transform‐polar.py).

Figure 2.5
Axes boundaries in polar projection using a transform from normalized data co‐
ordinates to data coordinates (coordinates/transform‐blend.py).

It seems that Figure 2.5 has incorrect description.

Thank you.

Alternative solution (Chapter 1, Exercise 3)

Hi @rougier,

Because Discussions are not enabled for this repository, I decided to share my alternative solution for ridgeline plot exercise as separate issue, because it is a slightly different approach, for clarity I added the comments for each step:

from matplotlib.patches import ConnectionPatch
import matplotlib.pyplot as plt
import numpy as np

# Initial function
def curve():
    n = np.random.randint(1,5)
    centers = np.random.normal(0.0,1.0,n)
    widths = np.random.uniform(5.0,50.0,n)
    widths = 10*widths/widths.sum()
    scales = np.random.uniform(0.1,1.0,n)
    scales /= scales.sum()
    X = np.zeros(500)
    x = np.linspace(-3,3,len(X))
    
    for center, width, scale in zip(centers, widths, scales):
        X = X + scale*np.exp(- (x-center)*(x-center)*width)
        
    return X

# Set random seed and subplots number
RANDOM_STATE = 25
np.random.seed(RANDOM_STATE)
rows = 50
cols = 3

# Configure figure and overlapping axes
fig, axs = plt.subplots(rows, cols, figsize=(10, rows*0.2), subplot_kw={'yticks': []})
plt.subplots_adjust(top=0.95, bottom=0.05, hspace=-0.5, wspace=0.1)

# Label columns with titles and rows with y-axis labels
# https://stackoverflow.com/a/25814386
row_names = [f'Serie {serie}' for serie in range(rows, 0, -1)]
col_names = [f'Value {value}' for value in range(1, cols + 1)]

for ax, name in zip(axs[:, 0], row_names):
    ax.set_ylabel(name, rotation=0, fontsize='small', loc='bottom', labelpad=40)
    
for ax, name in zip(axs[0], col_names):
    ax.set_title(name, fontsize='large', fontweight='bold', loc='left', pad=20)

# Control the degree of "softness/pastelness" of the colors (if required)
# https://stackoverflow.com/a/72289062
c = 0
colors = (1. - c) * plt.get_cmap('Spectral')(np.linspace(0, 1, rows)) + c * np.ones((rows, 4))
colors = colors[::-1]

# Plot graphs from left to right, from top to bottom
for idx in range(rows * cols):
    i = idx // cols
    j = idx % cols
    
    ax = axs[i][j]
    ax.set_facecolor('none')
    ax.spines[['left', 'top', 'right', 'bottom']].set_visible(False)
    
    if i != rows - 1:
        ax.get_xaxis().set_visible(False)
    
    y = curve()
    x = np.linspace(-3, 3, y.size)
    ax.plot(x, y, color='k', linewidth=1)
    ax.fill_between(x, y, color=colors[i])
    ax.set_zorder(i)

# Plot vertical lines for each column of subplots
for col_idx in range(cols):
    coords = axs[0][col_idx].get_position()
    zero_x_coords = (coords.x1 + coords.x0) / 2
    conn = ConnectionPatch(xyA=(zero_x_coords, 0.99), xyB=(0, 0), 
                           coordsA='figure fraction', coordsB='data', 
                           axesA=axs[0, col_idx], axesB=axs[rows-1, col_idx],
                           zorder=rows, linewidth=0.5, linestyle=(0, (8, 2)), color='k')
    fig.add_artist(conn)

plt.show()

Output image you can find in Jupyter notebook with exercises for Chapter 1.

Thank you.

module 'glm' has no attribute 'camera'

When I run this code,
`import glm
import plot
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt

-----------------------------------------------------------------------------

if name == "main":
from matplotlib.patches import Ellipse
from matplotlib.collections import PolyCollection

fig = plt.figure(figsize=(6, 6))
ax = fig.add_axes([0, 0, 1, 1])
camera = glm.camera(25, 45, 1, "perspective")
plot.axis(ax, camera)

np.random.seed(1)
n = 1024
P = 0.2 * np.random.normal(0, 1, (n, 3))

# Bottom shadow
V = glm.transform(P * [1, 0, 1] - [0, 0.5, 0], camera)
T = np.linspace(0, 2 * np.pi, 12)
radius = 0.015
X, Y, Z = radius * np.cos(T), np.zeros(len(T)), radius * np.sin(T)
C = np.c_[X, Y, Z]
polys = []
for i in range(n):
    V = glm.transform(C + [P[i, 0], -0.5, P[i, 2]], camera)[:, :2]
    polys.append(V)

collection = PolyCollection(
    polys, linewidths=0, alpha=0.5, zorder=+10, facecolors="0.5", edgecolor="none"
)
ax.add_collection(collection)

# Actual scatter
V = glm.transform(P, camera)
X, Y, Z = V[:, 0], V[:, 1], V[:, 2]
I = np.argsort(Z)
X, Y = X[I], Y[I]
facecolor = [
    (0, 0, 0, 0),
    (0, 0, 0, 0),
    (0, 0, 0, 0),
    mpl.colors.to_rgba("C4"),
    (1, 1, 1, 0.25),
    (1, 1, 1, 1),
] * len(X)
edgecolor = [
    (0, 0, 0, 0.05),
    (0, 0, 0, 0.10),
    (0, 0, 0, 0.15),
    (0, 0, 0, 1.00),
    (0, 0, 0, 0.00),
    (0, 0, 0, 0.00),
] * len(X)
linewidth = [6, 4, 2, 0.5, 0.0, 0.0] * len(X)
dX = (0, 0, 0, 0, -0.0035, -0.0035) * len(X)
dY = (0, 0, 0, 0, +0.0025, +0.0025) * len(Y)
size = np.array((1, 1, 1, 1, 0.25, 0.05) * len(X)) * 50
X, Y = np.repeat(X, 6), np.repeat(Y, 6)
ax.scatter(
    X + dX,
    Y + dY,
    s=size,
    linewidth=linewidth,
    zorder=10,
    facecolor=facecolor,
    edgecolor=edgecolor,
)

plt.savefig("scatter.png", dpi=300)
plt.savefig("scatter.pdf")
plt.show()`

the output shows that module 'glm' has no attribute 'camera' and module 'plot' has no attribute 'axis'.

Create recent book version from scratch

Hi @rougier,

Could you please tell is it possible to create recent version of the book using the repository by myself?

I started to install required system/python packages and have an errors when running make all, for example:

Latexmk: 'xelatex': source file 'ean13.tex' doesn't exist. I'll try making it...

There are a lot of fixes in repository which are not in pdf in the book folder, and it will be great to include these fixes in pdf version.

Thank you.

Code for Figure 2.6 from the book doesn't match the image (Chapter 2, pages 25-26)

Hi @rougier,

The code in the book for imshow() function which is used for collage plotting is not consistent with the output image and the Python file.
In addition to the missing lines (which is probably done intentionally), for example zorder is used in the body but there is no argument with the same name (in Python file there is a such argument).
Could you please tell maybe it's all done that way on intentionally and it is not necessary to create issues like this and #64?

Thank you.

Blank Pages?

Hi,
Thanks for the amazing work!

I have noticed there are blank pages(which also have page numbers). Is it actually the case or Its a issue of my device?

Reduce repetition in text (for example) in the anatomy chapter

Hello,

I found a typo in #23 , and next to it there are two "For example", one next to the other. I think we could reduce repetition by removing or replacing one of these two, but not sure what would be the best solution. Sorry.

Here's where it happens:

image

Also, maybe it would be clearer to show in the former case that GtkCairo stands for Gtk3 interface + Cairo renderer I think? Might be helpful to complete beginners.

Cheers
Bruno

ePUB Release

Thank you, and well done on the release of this fantastic and comprehensive book! I wondered whether you might consider releasing an ePUB edition of it at all? Many thanks!

Fig 1.8 not referenced in text

There is no reference to Figure 1.8 in the exercises at the end of Chapter 1. Maybe it is supposed to be associated with Exercise 1 (produce a figure with an exact pixel size)? If so, some reference to the figure in that section of the text would be helpful. And if it is supposed to be an example of setting exact figure pixel size, the code for Fig 1.8 could be more specific about defining what the figure pixel size is.

As a side note, the method of generating Fig 1.8 is interesting but perhaps unnecessarily complicated for this part of the book? Is it demonstrating something discussed in Chapter 1?

Web version

Could you consider having a web version? i.e through github pages?

image

AttributeError: 'Arrow3D' object has no attribute 'do_3d_projection'

I try to run code/scales-projections/projection-3d-frame.py
and then there's an error: AttributeError: 'Arrow3D' object has no attribute 'do_3d_projection'

my env: python: 3.11, matplotlib: 3.8.0

then I found a possible solution here -> matplotlib issues#21688
when I change class Arrow3D to :

class Arrow3D(mpatches.FancyArrowPatch):
    def __init__(self, xs, ys, zs, *args, **kwargs):
        mpatches.FancyArrowPatch.__init__(self, (0, 0), (0, 0), *args, **kwargs)
        self._verts3d = xs, ys, zs

    def do_3d_projection(self, renderer=None):
        xs3d, ys3d, zs3d = self._verts3d
        xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, self.axes.M)
        self.set_positions((xs[0],ys[0]),(xs[1],ys[1]))
        return np.min(zs)

it works, so I think maybe projection-3d-frame.py need to be updated?

Link to antigrain.com is not working (Chapter 1, page 8)

Hi @rougier,

I found that the link under "Anti‐Grain Geometry C++ library" to https://antigrain.com is not working, and it is confirmed in the description here, referring also to another site (http://agg.sourceforge.net/antigrain.com/):

The official AGG site remains on Sourceforge, but doesn't see much activity. With www.antigrain.com recently inoperational, I thought a GitHub repo was in order, as the project demos stopped building with the site down.

Thank you.

Colon character (:) not rendering properly in PDF

In the chapter "10 simple rules", around line 276 (I'd link it directly but GH doesn't seem to support line numbers properly with RST files), there's this sentence:

   first one (30), while the ratio between the two values is only 3∶1. This

The character doesn't seem to be rendered properly no matter which PDF viewer I use (Evince, Okular on Linux, Adobe Reader on Win10), and looks like this:
image
I tried building the book on my machine but still end up with the same issue.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.