Cartoon Style Drawing for HTML5 Canvas & Raphael.js & D3.js & SVG.js

comic.js

Javascript library that acts as plugin for Raphael.js, D3.js, SVG.js or as lib for the HTML5 Canvas, providing functions for cartoon style drawing. Try it in the comic.js lab.

Provides either methods for drawing comic style shapes (cEllipse, cLine, cRect, ...) or the magic method for cartoonizing an already existing SVG. When using the magic method or drawing on a canvas no further libraries are required.

screenshot screenshot

Examples

Cartoonized D3 examples: D3 Cartoonized!

Cartoon R widget built by Kent Russell using comic.js: R Cartoonized!

using raphael.js, d3.js, svg.js and canvas: comic.js lab

using "magic": on images, on drawings

NOTE

Chrome versions > 48.x need a polyfill for the missing pathSegList API to make the magic method of comic.js work. This means you have to get pathseg.js here and include it in your site via <script type="text/javascript" src="pathseg.js"></script>.

Usage

Simply include comic.min.js after including one of the supported libraries (Raphael.js, D3.js, SVG.js) - or none of them if you are using a HTML5 Canvas or just the magic function for images. Then it can be used as follows, assuming that you have a container div or canvas with id paper where needed:

The "magic" function universally goes:

// for images
COMIC.magic([ document.getElementById('img1'),
              document.getElementById('img2') ]);
// for drawings
shapes.magic(); // where "shapes" is a drawing group created on "paper"
                // via the lib of your choice (see examples below)

Drawing depending on the lib you use:

// Raphael.js
paper = Raphael("paper", width, height);
stuff = paper.set();

or

// D3.js
paper = d3.select("#paper").append('svg');
stuff = paper.append("g");

or

// SVG.js
paper = SVG('paper').size(width, height);
stuff = paper.group();

or

// canvas
paper = document.getElementById("paper");
ctx = paper.getContext("2d");
// IMPORTANT: here we bind comic.js to the canvas context
COMIC.ctx(ctx);

and then for the SVG libs (SVG.js, D3.js, Raphael.js):

// these are the default values if you do not call "init"
// NOTE: values have changed with beta5
COMIC.init({
    ff: 8,      // fuzz factor for line drawing: bigger -> fuzzier
    ffc: 5,     // fuzz factor for curve drawing: bigger -> fuzzier
    fsteps: 5,  // number of pixels per step: smaller -> fuzzier
    msteps: 3,  // min number of steps: bigger -> fuzzier
});
// lets draw!
stuff.cLine(x1, y1, x2, y2);         // LINE from starting point to end point
stuff.cTrian(x1, y1, x2, y2, x3, y3); // TRIANGLE over three corner points
stuff.cRect(x1, y1, width, height, rh, rv); // RECTANGLE at upper left point (x1, y1) with
                                            // width & height and with rounded (elliptic) corners
                                            // with horizontal radius rh & vertical radius rv
stuff.cBezier2(x1, y1, cx, cy, x2, y2); // BEZIER (quadratic) curve with start point (x1, y1),
                                        // control point (cx, cy) and end point (x2, y2)
stuff.cBezier3(x1, y1, cx1, cy1, cx2, cy2, x2, y2); // BEZIER (cubic) curve with start point
                                                    // (x1, y1), control points (cx1, cy1) & (cx2, cy2)
                                                    // and end point (x2, y2)
stuff.cCircle(x1, y1, r, start, end); // CIRCLE at center point (x1, y1) with radius r and drawn
                                      // starting from 0 < start < 2*PI to 0 < end < 2*PI
stuff.cEllipse(x1, y1, rh, rv, rot, start, end); // ELLIPSE at center point with horizontal radius
                                                 // rh & vertical radius rv, rotation 0 < rot < 2*PI
                                                 // and drawn from 0 < start < 2*PI to 0 < end < 2*PI
// changing the look
stuff.attr({
    "stroke":"#E0AE9F",
    "stroke-width": 2,
    "fill": "none"
});

Beyond this all depends on your choice of library - e.g. translation:

// Raphael.js
stuff.transform("t100,100r45");
// D3.js
stuff.attr({ "transform":"translate(30) rotate(45)" });
// SVG.js
stuff.transform({ x:100, y:100, rotation:45 });

For the HTML5 Canvas almost everything works identically. However to change the looks:

// changing the look
ctx.strokeStyle = "#FDD1BD";
ctx.lineWidth = 3;
ctx.globalCompositeOperation = 'destination-over';

While the drawing works exactly as above:

// lets draw!
stuff.cLine(x1, y1, x2, y2)
     .cTrian(x1, y1, x2, y2, x3, y3)
     .cRect(x1, y1, width, height);

All further things should work the default way of your chosen library. I have done little experiments though and errors are probable - please let me know if you encounter any.

Credits

Inspired by and based on Jonas Wagner's work which is based on this paper

Author: Balint42
Source Code: https://github.com/balint42/comic.js 
License: MIT license

#javascript #d3 #svg #html5 

What is GEEK

Buddha Community

Cartoon Style Drawing for HTML5 Canvas & Raphael.js & D3.js & SVG.js

Cartoon Style Drawing for HTML5 Canvas & Raphael.js & D3.js & SVG.js

comic.js

Javascript library that acts as plugin for Raphael.js, D3.js, SVG.js or as lib for the HTML5 Canvas, providing functions for cartoon style drawing. Try it in the comic.js lab.

Provides either methods for drawing comic style shapes (cEllipse, cLine, cRect, ...) or the magic method for cartoonizing an already existing SVG. When using the magic method or drawing on a canvas no further libraries are required.

screenshot screenshot

Examples

Cartoonized D3 examples: D3 Cartoonized!

Cartoon R widget built by Kent Russell using comic.js: R Cartoonized!

using raphael.js, d3.js, svg.js and canvas: comic.js lab

using "magic": on images, on drawings

NOTE

Chrome versions > 48.x need a polyfill for the missing pathSegList API to make the magic method of comic.js work. This means you have to get pathseg.js here and include it in your site via <script type="text/javascript" src="pathseg.js"></script>.

Usage

Simply include comic.min.js after including one of the supported libraries (Raphael.js, D3.js, SVG.js) - or none of them if you are using a HTML5 Canvas or just the magic function for images. Then it can be used as follows, assuming that you have a container div or canvas with id paper where needed:

The "magic" function universally goes:

// for images
COMIC.magic([ document.getElementById('img1'),
              document.getElementById('img2') ]);
// for drawings
shapes.magic(); // where "shapes" is a drawing group created on "paper"
                // via the lib of your choice (see examples below)

Drawing depending on the lib you use:

// Raphael.js
paper = Raphael("paper", width, height);
stuff = paper.set();

or

// D3.js
paper = d3.select("#paper").append('svg');
stuff = paper.append("g");

or

// SVG.js
paper = SVG('paper').size(width, height);
stuff = paper.group();

or

// canvas
paper = document.getElementById("paper");
ctx = paper.getContext("2d");
// IMPORTANT: here we bind comic.js to the canvas context
COMIC.ctx(ctx);

and then for the SVG libs (SVG.js, D3.js, Raphael.js):

// these are the default values if you do not call "init"
// NOTE: values have changed with beta5
COMIC.init({
    ff: 8,      // fuzz factor for line drawing: bigger -> fuzzier
    ffc: 5,     // fuzz factor for curve drawing: bigger -> fuzzier
    fsteps: 5,  // number of pixels per step: smaller -> fuzzier
    msteps: 3,  // min number of steps: bigger -> fuzzier
});
// lets draw!
stuff.cLine(x1, y1, x2, y2);         // LINE from starting point to end point
stuff.cTrian(x1, y1, x2, y2, x3, y3); // TRIANGLE over three corner points
stuff.cRect(x1, y1, width, height, rh, rv); // RECTANGLE at upper left point (x1, y1) with
                                            // width & height and with rounded (elliptic) corners
                                            // with horizontal radius rh & vertical radius rv
stuff.cBezier2(x1, y1, cx, cy, x2, y2); // BEZIER (quadratic) curve with start point (x1, y1),
                                        // control point (cx, cy) and end point (x2, y2)
stuff.cBezier3(x1, y1, cx1, cy1, cx2, cy2, x2, y2); // BEZIER (cubic) curve with start point
                                                    // (x1, y1), control points (cx1, cy1) & (cx2, cy2)
                                                    // and end point (x2, y2)
stuff.cCircle(x1, y1, r, start, end); // CIRCLE at center point (x1, y1) with radius r and drawn
                                      // starting from 0 < start < 2*PI to 0 < end < 2*PI
stuff.cEllipse(x1, y1, rh, rv, rot, start, end); // ELLIPSE at center point with horizontal radius
                                                 // rh & vertical radius rv, rotation 0 < rot < 2*PI
                                                 // and drawn from 0 < start < 2*PI to 0 < end < 2*PI
// changing the look
stuff.attr({
    "stroke":"#E0AE9F",
    "stroke-width": 2,
    "fill": "none"
});

Beyond this all depends on your choice of library - e.g. translation:

// Raphael.js
stuff.transform("t100,100r45");
// D3.js
stuff.attr({ "transform":"translate(30) rotate(45)" });
// SVG.js
stuff.transform({ x:100, y:100, rotation:45 });

For the HTML5 Canvas almost everything works identically. However to change the looks:

// changing the look
ctx.strokeStyle = "#FDD1BD";
ctx.lineWidth = 3;
ctx.globalCompositeOperation = 'destination-over';

While the drawing works exactly as above:

// lets draw!
stuff.cLine(x1, y1, x2, y2)
     .cTrian(x1, y1, x2, y2, x3, y3)
     .cRect(x1, y1, width, height);

All further things should work the default way of your chosen library. I have done little experiments though and errors are probable - please let me know if you encounter any.

Credits

Inspired by and based on Jonas Wagner's work which is based on this paper

Author: Balint42
Source Code: https://github.com/balint42/comic.js 
License: MIT license

#javascript #d3 #svg #html5 

NBB: Ad-hoc CLJS Scripting on Node.js

Nbb

Not babashka. Node.js babashka!?

Ad-hoc CLJS scripting on Node.js.

Status

Experimental. Please report issues here.

Goals and features

Nbb's main goal is to make it easy to get started with ad hoc CLJS scripting on Node.js.

Additional goals and features are:

  • Fast startup without relying on a custom version of Node.js.
  • Small artifact (current size is around 1.2MB).
  • First class macros.
  • Support building small TUI apps using Reagent.
  • Complement babashka with libraries from the Node.js ecosystem.

Requirements

Nbb requires Node.js v12 or newer.

How does this tool work?

CLJS code is evaluated through SCI, the same interpreter that powers babashka. Because SCI works with advanced compilation, the bundle size, especially when combined with other dependencies, is smaller than what you get with self-hosted CLJS. That makes startup faster. The trade-off is that execution is less performant and that only a subset of CLJS is available (e.g. no deftype, yet).

Usage

Install nbb from NPM:

$ npm install nbb -g

Omit -g for a local install.

Try out an expression:

$ nbb -e '(+ 1 2 3)'
6

And then install some other NPM libraries to use in the script. E.g.:

$ npm install csv-parse shelljs zx

Create a script which uses the NPM libraries:

(ns script
  (:require ["csv-parse/lib/sync$default" :as csv-parse]
            ["fs" :as fs]
            ["path" :as path]
            ["shelljs$default" :as sh]
            ["term-size$default" :as term-size]
            ["zx$default" :as zx]
            ["zx$fs" :as zxfs]
            [nbb.core :refer [*file*]]))

(prn (path/resolve "."))

(prn (term-size))

(println (count (str (fs/readFileSync *file*))))

(prn (sh/ls "."))

(prn (csv-parse "foo,bar"))

(prn (zxfs/existsSync *file*))

(zx/$ #js ["ls"])

Call the script:

$ nbb script.cljs
"/private/tmp/test-script"
#js {:columns 216, :rows 47}
510
#js ["node_modules" "package-lock.json" "package.json" "script.cljs"]
#js [#js ["foo" "bar"]]
true
$ ls
node_modules
package-lock.json
package.json
script.cljs

Macros

Nbb has first class support for macros: you can define them right inside your .cljs file, like you are used to from JVM Clojure. Consider the plet macro to make working with promises more palatable:

(defmacro plet
  [bindings & body]
  (let [binding-pairs (reverse (partition 2 bindings))
        body (cons 'do body)]
    (reduce (fn [body [sym expr]]
              (let [expr (list '.resolve 'js/Promise expr)]
                (list '.then expr (list 'clojure.core/fn (vector sym)
                                        body))))
            body
            binding-pairs)))

Using this macro we can look async code more like sync code. Consider this puppeteer example:

(-> (.launch puppeteer)
      (.then (fn [browser]
               (-> (.newPage browser)
                   (.then (fn [page]
                            (-> (.goto page "https://clojure.org")
                                (.then #(.screenshot page #js{:path "screenshot.png"}))
                                (.catch #(js/console.log %))
                                (.then #(.close browser)))))))))

Using plet this becomes:

(plet [browser (.launch puppeteer)
       page (.newPage browser)
       _ (.goto page "https://clojure.org")
       _ (-> (.screenshot page #js{:path "screenshot.png"})
             (.catch #(js/console.log %)))]
      (.close browser))

See the puppeteer example for the full code.

Since v0.0.36, nbb includes promesa which is a library to deal with promises. The above plet macro is similar to promesa.core/let.

Startup time

$ time nbb -e '(+ 1 2 3)'
6
nbb -e '(+ 1 2 3)'   0.17s  user 0.02s system 109% cpu 0.168 total

The baseline startup time for a script is about 170ms seconds on my laptop. When invoked via npx this adds another 300ms or so, so for faster startup, either use a globally installed nbb or use $(npm bin)/nbb script.cljs to bypass npx.

Dependencies

NPM dependencies

Nbb does not depend on any NPM dependencies. All NPM libraries loaded by a script are resolved relative to that script. When using the Reagent module, React is resolved in the same way as any other NPM library.

Classpath

To load .cljs files from local paths or dependencies, you can use the --classpath argument. The current dir is added to the classpath automatically. So if there is a file foo/bar.cljs relative to your current dir, then you can load it via (:require [foo.bar :as fb]). Note that nbb uses the same naming conventions for namespaces and directories as other Clojure tools: foo-bar in the namespace name becomes foo_bar in the directory name.

To load dependencies from the Clojure ecosystem, you can use the Clojure CLI or babashka to download them and produce a classpath:

$ classpath="$(clojure -A:nbb -Spath -Sdeps '{:aliases {:nbb {:replace-deps {com.github.seancorfield/honeysql {:git/tag "v2.0.0-rc5" :git/sha "01c3a55"}}}}}')"

and then feed it to the --classpath argument:

$ nbb --classpath "$classpath" -e "(require '[honey.sql :as sql]) (sql/format {:select :foo :from :bar :where [:= :baz 2]})"
["SELECT foo FROM bar WHERE baz = ?" 2]

Currently nbb only reads from directories, not jar files, so you are encouraged to use git libs. Support for .jar files will be added later.

Current file

The name of the file that is currently being executed is available via nbb.core/*file* or on the metadata of vars:

(ns foo
  (:require [nbb.core :refer [*file*]]))

(prn *file*) ;; "/private/tmp/foo.cljs"

(defn f [])
(prn (:file (meta #'f))) ;; "/private/tmp/foo.cljs"

Reagent

Nbb includes reagent.core which will be lazily loaded when required. You can use this together with ink to create a TUI application:

$ npm install ink

ink-demo.cljs:

(ns ink-demo
  (:require ["ink" :refer [render Text]]
            [reagent.core :as r]))

(defonce state (r/atom 0))

(doseq [n (range 1 11)]
  (js/setTimeout #(swap! state inc) (* n 500)))

(defn hello []
  [:> Text {:color "green"} "Hello, world! " @state])

(render (r/as-element [hello]))

Promesa

Working with callbacks and promises can become tedious. Since nbb v0.0.36 the promesa.core namespace is included with the let and do! macros. An example:

(ns prom
  (:require [promesa.core :as p]))

(defn sleep [ms]
  (js/Promise.
   (fn [resolve _]
     (js/setTimeout resolve ms))))

(defn do-stuff
  []
  (p/do!
   (println "Doing stuff which takes a while")
   (sleep 1000)
   1))

(p/let [a (do-stuff)
        b (inc a)
        c (do-stuff)
        d (+ b c)]
  (prn d))
$ nbb prom.cljs
Doing stuff which takes a while
Doing stuff which takes a while
3

Also see API docs.

Js-interop

Since nbb v0.0.75 applied-science/js-interop is available:

(ns example
  (:require [applied-science.js-interop :as j]))

(def o (j/lit {:a 1 :b 2 :c {:d 1}}))

(prn (j/select-keys o [:a :b])) ;; #js {:a 1, :b 2}
(prn (j/get-in o [:c :d])) ;; 1

Most of this library is supported in nbb, except the following:

  • destructuring using :syms
  • property access using .-x notation. In nbb, you must use keywords.

See the example of what is currently supported.

Examples

See the examples directory for small examples.

Also check out these projects built with nbb:

API

See API documentation.

Migrating to shadow-cljs

See this gist on how to convert an nbb script or project to shadow-cljs.

Build

Prequisites:

  • babashka >= 0.4.0
  • Clojure CLI >= 1.10.3.933
  • Node.js 16.5.0 (lower version may work, but this is the one I used to build)

To build:

  • Clone and cd into this repo
  • bb release

Run bb tasks for more project-related tasks.

Download Details:
Author: borkdude
Download Link: Download The Source Code
Official Website: https://github.com/borkdude/nbb 
License: EPL-1.0

#node #javascript

Dylan  Iqbal

Dylan Iqbal

1561523460

Matplotlib Cheat Sheet: Plotting in Python

This Matplotlib cheat sheet introduces you to the basics that you need to plot your data with Python and includes code samples.

Data visualization and storytelling with your data are essential skills that every data scientist needs to communicate insights gained from analyses effectively to any audience out there. 

For most beginners, the first package that they use to get in touch with data visualization and storytelling is, naturally, Matplotlib: it is a Python 2D plotting library that enables users to make publication-quality figures. But, what might be even more convincing is the fact that other packages, such as Pandas, intend to build more plotting integration with Matplotlib as time goes on.

However, what might slow down beginners is the fact that this package is pretty extensive. There is so much that you can do with it and it might be hard to still keep a structure when you're learning how to work with Matplotlib.   

DataCamp has created a Matplotlib cheat sheet for those who might already know how to use the package to their advantage to make beautiful plots in Python, but that still want to keep a one-page reference handy. Of course, for those who don't know how to work with Matplotlib, this might be the extra push be convinced and to finally get started with data visualization in Python. 

You'll see that this cheat sheet presents you with the six basic steps that you can go through to make beautiful plots. 

Check out the infographic by clicking on the button below:

Python Matplotlib cheat sheet

With this handy reference, you'll familiarize yourself in no time with the basics of Matplotlib: you'll learn how you can prepare your data, create a new plot, use some basic plotting routines to your advantage, add customizations to your plots, and save, show and close the plots that you make.

What might have looked difficult before will definitely be more clear once you start using this cheat sheet! Use it in combination with the Matplotlib Gallery, the documentation.

Matplotlib 

Matplotlib is a Python 2D plotting library which produces publication-quality figures in a variety of hardcopy formats and interactive environments across platforms.

Prepare the Data 

1D Data 

>>> import numpy as np
>>> x = np.linspace(0, 10, 100)
>>> y = np.cos(x)
>>> z = np.sin(x)

2D Data or Images 

>>> data = 2 * np.random.random((10, 10))
>>> data2 = 3 * np.random.random((10, 10))
>>> Y, X = np.mgrid[-3:3:100j, -3:3:100j]
>>> U = 1 X** 2 + Y
>>> V = 1 + X Y**2
>>> from matplotlib.cbook import get_sample_data
>>> img = np.load(get_sample_data('axes_grid/bivariate_normal.npy'))

Create Plot

>>> import matplotlib.pyplot as plt

Figure 

>>> fig = plt.figure()
>>> fig2 = plt.figure(figsize=plt.figaspect(2.0))

Axes 

>>> fig.add_axes()
>>> ax1 = fig.add_subplot(221) #row-col-num
>>> ax3 = fig.add_subplot(212)
>>> fig3, axes = plt.subplots(nrows=2,ncols=2)
>>> fig4, axes2 = plt.subplots(ncols=3)

Save Plot 

>>> plt.savefig('foo.png') #Save figures
>>> plt.savefig('foo.png',  transparent=True) #Save transparent figures

Show Plot

>>> plt.show()

Plotting Routines 

1D Data 

>>> fig, ax = plt.subplots()
>>> lines = ax.plot(x,y) #Draw points with lines or markers connecting them
>>> ax.scatter(x,y) #Draw unconnected points, scaled or colored
>>> axes[0,0].bar([1,2,3],[3,4,5]) #Plot vertical rectangles (constant width)
>>> axes[1,0].barh([0.5,1,2.5],[0,1,2]) #Plot horiontal rectangles (constant height)
>>> axes[1,1].axhline(0.45) #Draw a horizontal line across axes
>>> axes[0,1].axvline(0.65) #Draw a vertical line across axes
>>> ax.fill(x,y,color='blue') #Draw filled polygons
>>> ax.fill_between(x,y,color='yellow') #Fill between y values and 0

2D Data 

>>> fig, ax = plt.subplots()
>>> im = ax.imshow(img, #Colormapped or RGB arrays
      cmap= 'gist_earth', 
      interpolation= 'nearest',
      vmin=-2,
      vmax=2)
>>> axes2[0].pcolor(data2) #Pseudocolor plot of 2D array
>>> axes2[0].pcolormesh(data) #Pseudocolor plot of 2D array
>>> CS = plt.contour(Y,X,U) #Plot contours
>>> axes2[2].contourf(data1) #Plot filled contours
>>> axes2[2]= ax.clabel(CS) #Label a contour plot

Vector Fields 

>>> axes[0,1].arrow(0,0,0.5,0.5) #Add an arrow to the axes
>>> axes[1,1].quiver(y,z) #Plot a 2D field of arrows
>>> axes[0,1].streamplot(X,Y,U,V) #Plot a 2D field of arrows

Data Distributions 

>>> ax1.hist(y) #Plot a histogram
>>> ax3.boxplot(y) #Make a box and whisker plot
>>> ax3.violinplot(z)  #Make a violin plot

Plot Anatomy & Workflow 

Plot Anatomy 

 y-axis      

                           x-axis 

Workflow 

The basic steps to creating plots with matplotlib are:

1 Prepare Data
2 Create Plot
3 Plot
4 Customized Plot
5 Save Plot
6 Show Plot

>>> import matplotlib.pyplot as plt
>>> x = [1,2,3,4]  #Step 1
>>> y = [10,20,25,30] 
>>> fig = plt.figure() #Step 2
>>> ax = fig.add_subplot(111) #Step 3
>>> ax.plot(x, y, color= 'lightblue', linewidth=3)  #Step 3, 4
>>> ax.scatter([2,4,6],
          [5,15,25],
          color= 'darkgreen',
          marker= '^' )
>>> ax.set_xlim(1, 6.5)
>>> plt.savefig('foo.png' ) #Step 5
>>> plt.show() #Step 6

Close and Clear 

>>> plt.cla()  #Clear an axis
>>> plt.clf(). #Clear the entire figure
>>> plt.close(). #Close a window

Plotting Customize Plot 

Colors, Color Bars & Color Maps 

>>> plt.plot(x, x, x, x**2, x, x** 3)
>>> ax.plot(x, y, alpha = 0.4)
>>> ax.plot(x, y, c= 'k')
>>> fig.colorbar(im, orientation= 'horizontal')
>>> im = ax.imshow(img,
            cmap= 'seismic' )

Markers 

>>> fig, ax = plt.subplots()
>>> ax.scatter(x,y,marker= ".")
>>> ax.plot(x,y,marker= "o")

Linestyles 

>>> plt.plot(x,y,linewidth=4.0)
>>> plt.plot(x,y,ls= 'solid') 
>>> plt.plot(x,y,ls= '--') 
>>> plt.plot(x,y,'--' ,x**2,y**2,'-.' ) 
>>> plt.setp(lines,color= 'r',linewidth=4.0)

Text & Annotations 

>>> ax.text(1,
           -2.1, 
           'Example Graph', 
            style= 'italic' )
>>> ax.annotate("Sine", 
xy=(8, 0),
xycoords= 'data', 
xytext=(10.5, 0),
textcoords= 'data', 
arrowprops=dict(arrowstyle= "->", 
connectionstyle="arc3"),)

Mathtext 

>>> plt.title(r '$sigma_i=15$', fontsize=20)

Limits, Legends and Layouts 

Limits & Autoscaling 

>>> ax.margins(x=0.0,y=0.1) #Add padding to a plot
>>> ax.axis('equal')  #Set the aspect ratio of the plot to 1
>>> ax.set(xlim=[0,10.5],ylim=[-1.5,1.5])  #Set limits for x-and y-axis
>>> ax.set_xlim(0,10.5) #Set limits for x-axis

Legends 

>>> ax.set(title= 'An Example Axes',  #Set a title and x-and y-axis labels
            ylabel= 'Y-Axis', 
            xlabel= 'X-Axis')
>>> ax.legend(loc= 'best')  #No overlapping plot elements

Ticks 

>>> ax.xaxis.set(ticks=range(1,5),  #Manually set x-ticks
             ticklabels=[3,100, 12,"foo" ])
>>> ax.tick_params(axis= 'y', #Make y-ticks longer and go in and out
             direction= 'inout', 
              length=10)

Subplot Spacing 

>>> fig3.subplots_adjust(wspace=0.5,   #Adjust the spacing between subplots
             hspace=0.3,
             left=0.125,
             right=0.9,
             top=0.9,
             bottom=0.1)
>>> fig.tight_layout() #Fit subplot(s) in to the figure area

Axis Spines 

>>> ax1.spines[ 'top'].set_visible(False) #Make the top axis line for a plot invisible
>>> ax1.spines['bottom' ].set_position(( 'outward',10))  #Move the bottom axis line outward

Have this Cheat Sheet at your fingertips

Original article source at https://www.datacamp.com

#matplotlib #cheatsheet #python

Generates an Image from a DOM Node using HTML5 Canvas and SVG

html-to-image

Generates an image from a DOM node using HTML5 canvas and SVG.

Fork from dom-to-image with more maintainable code and some new features.

Install

npm install --save html-to-image

Usage

/* ES6 */
import * as htmlToImage from 'html-to-image';
import { toPng, toJpeg, toBlob, toPixelData, toSvg } from 'html-to-image';

/* ES5 */
var htmlToImage = require('html-to-image');

All the top level functions accept DOM node and rendering options, and return a promise fulfilled with corresponding dataURL:

Go with the following examples.

toPng

Get a PNG image base64-encoded data URL and display it right away:

var node = document.getElementById('my-node');

htmlToImage.toPng(node)
  .then(function (dataUrl) {
    var img = new Image();
    img.src = dataUrl;
    document.body.appendChild(img);
  })
  .catch(function (error) {
    console.error('oops, something went wrong!', error);
  });

Get a PNG image base64-encoded data URL and download it (using download):

htmlToImage.toPng(document.getElementById('my-node'))
  .then(function (dataUrl) {
    download(dataUrl, 'my-node.png');
  });

toSvg

Get an SVG data URL, but filter out all the <i> elements:

function filter (node) {
  return (node.tagName !== 'i');
}

htmlToImage.toSvg(document.getElementById('my-node'), { filter: filter })
  .then(function (dataUrl) {
    /* do something */
  });

toJpeg

Save and download a compressed JPEG image:

htmlToImage.toJpeg(document.getElementById('my-node'), { quality: 0.95 })
  .then(function (dataUrl) {
    var link = document.createElement('a');
    link.download = 'my-image-name.jpeg';
    link.href = dataUrl;
    link.click();
  });

toBlob

Get a PNG image blob and download it (using FileSaver):

htmlToImage.toBlob(document.getElementById('my-node'))
  .then(function (blob) {
    window.saveAs(blob, 'my-node.png');
  });

toCanvas

Get a HTMLCanvasElement, and display it right away:

htmlToImage.toCanvas(document.getElementById('my-node'))
  .then(function (canvas) {
    document.body.appendChild(canvas);
  });

toPixelData

Get the raw pixel data as a Uint8Array with every 4 array elements representing the RGBA data of a pixel:

var node = document.getElementById('my-node');

htmlToImage.toPixelData(node)
  .then(function (pixels) {
    for (var y = 0; y < node.scrollHeight; ++y) {
      for (var x = 0; x < node.scrollWidth; ++x) {
        pixelAtXYOffset = (4 * y * node.scrollHeight) + (4 * x);
        /* pixelAtXY is a Uint8Array[4] containing RGBA values of the pixel at (x, y) in the range 0..255 */
        pixelAtXY = pixels.slice(pixelAtXYOffset, pixelAtXYOffset + 4);
      }
    }
  });

React

import React, { useCallback, useRef } from 'react';
import { toPng } from 'html-to-image';

const App: React.FC = () => {
  const ref = useRef<HTMLDivElement>(null)

  const onButtonClick = useCallback(() => {
    if (ref.current === null) {
      return
    }

    toPng(ref.current, { cacheBust: true, })
      .then((dataUrl) => {
        const link = document.createElement('a')
        link.download = 'my-image-name.png'
        link.href = dataUrl
        link.click()
      })
      .catch((err) => {
        console.log(err)
      })
  }, [ref])

  return (
    <>
      <div ref={ref}>
      {/* DOM nodes you want to convert to PNG */}
      </div>
      <button onClick={onButtonClick}>Click me</button>
    </>
  )
}

Options

filter

(domNode: HTMLElement) => boolean

A function taking DOM node as argument. Should return true if passed node should be included in the output. Excluding node means excluding it's children as well.

Not called on the root node.

backgroundColor

A string value for the background color, any valid CSS color value.

width, height

Width and height in pixels to be applied to node before rendering.

canvasWidth, canvasHeight

Allows to scale the canva's size including the elements inside to a given width and height (in pixels).

style

An object whose properties to be copied to node's style before rendering. You might want to check this reference for JavaScript names of CSS properties.

quality

A number between 0 and 1 indicating image quality (e.g. 0.92 => 92%) of the JPEG image.

Defaults to 1.0 (100%)

cacheBust

Set to true to append the current time as a query string to URL requests to enable cache busting.

Defaults to false

imagePlaceholder

A data URL for a placeholder image that will be used when fetching an image fails.

Defaults to an empty string and will render empty areas for failed images.

pixelRatio

The pixel ratio of the captured image. Default use the actual pixel ratio of the device. Set 1 to use as initial-scale 1 for the image.

preferredFontFormat

The format required for font embedding. This is a useful optimisation when a webfont provider specifies several different formats for fonts in the CSS, for example:

@font-face {
  name: 'proxima-nova';
  src: url("...") format("woff2"), url("...") format("woff"), url("...") format("opentype");
}

Instead of embedding each format, all formats other than the one specified will be discarded. If this option is not specified then all formats will be downloaded and embedded.

fontEmbedCss

When supplied, the library will skip the process of parsing and embedding webfont URLs in CSS, instead using this value. This is useful when combined with .getFontEmbedCss() to only perform the embedding process a single time across multiple calls to library functions.

const fontEmbedCss = await htmlToImage.getFontEmbedCss(element1);
html2Image.toSVG(element1, { fontEmbedCss });
html2Image.toSVG(element2, { fontEmbedCss });

Browsers

Only standard lib is currently used, but make sure your browser supports:

It's tested on latest Chrome and Firefox (49 and 45 respectively at the time of writing), with Chrome performing significantly better on big DOM trees, possibly due to it's more performant SVG support, and the fact that it supports CSSStyleDeclaration.cssText property.

Internet Explorer is not (and will not be) supported, as it does not support SVG <foreignObject> tag.

Safari is not supported, as it uses a stricter security model on <foreignObject> tag. Suggested workaround is to use toSvg and render on the server.

How it works

There might some day exist (or maybe already exists?) a simple and standard way of exporting parts of the HTML to image (and then this script can only serve as an evidence of all the hoops I had to jump through in order to get such obvious thing done) but I haven't found one so far.

This library uses a feature of SVG that allows having arbitrary HTML content inside of the <foreignObject> tag. So, in order to render that DOM node for you, following steps are taken:

  1. Clone the original DOM node recursively
  2. Compute the style for the node and each sub-node and copy it to corresponding clone
    • and don't forget to recreate pseudo-elements, as they are not cloned in any way, of course
  3. Embed web fonts
    • find all the @font-face declarations that might represent web fonts
    • parse file URLs, download corresponding files
    • base64-encode and inline content as dataURLs
    • concatenate all the processed CSS rules and put them into one <style> element, then attach it to the clone
  4. Embed images
    • embed image URLs in <img> elements
    • inline images used in background CSS property, in a fashion similar to fonts
  5. Serialize the cloned node to XML
  6. Wrap XML into the <foreignObject> tag, then into the SVG, then make it a data URL
  7. Optionally, to get PNG content or raw pixel data as a Uint8Array, create an Image element with the SVG as a source, and render it on an off-screen canvas, that you have also created, then read the content from the canvas
  8. Done!

Things to watch out for

  • If the DOM node you want to render includes a <canvas> element with something drawn on it, it should be handled fine, unless the canvas is tainted - in this case rendering will rather not succeed.
  • Rendering will failed on huge DOM due to the dataURI limit varies.

Contributing

Pull requests and stars are highly welcome.

For bugs and feature requests, please create an issue.

Download Details:

Author: bubkoo
Download Link: Download The Source Code
Official Website: https://github.com/bubkoo/html-to-image
License: MIT

#Image #HTML5 #Canvas #SVG

Lawrence  Lesch

Lawrence Lesch

1664456280

Signature_pad: HTML5 Canvas Based Smooth Signature Drawing

Signature Pad

Signature Pad is a JavaScript library for drawing smooth signatures. It's HTML5 canvas based and uses variable width B├ęzier curve interpolation based on Smoother Signatures post by Square. It works in all modern desktop and mobile browsers and doesn't depend on any external libraries.

Installation

You can install the latest release using npm:

npm install --save signature_pad

or Yarn:

yarn add signature_pad

You can also add it directly to your page using <script> tag:

<script src="https://cdn.jsdelivr.net/npm/signature_pad@4.0.0/dist/signature_pad.umd.min.js"></script>

You can select a different version at https://www.jsdelivr.com/package/npm/signature_pad.

This library is provided as UMD (Universal Module Definition) and ES6 module.

Usage

API

const canvas = document.querySelector("canvas");

const signaturePad = new SignaturePad(canvas);

// Returns signature image as data URL (see https://mdn.io/todataurl for the list of possible parameters)
signaturePad.toDataURL(); // save image as PNG
signaturePad.toDataURL("image/jpeg"); // save image as JPEG
signaturePad.toDataURL("image/jpeg", 0.5); // save image as JPEG with 0.5 image quality
signaturePad.toDataURL("image/svg+xml"); // save image as SVG

// Draws signature image from data URL (mostly uses https://mdn.io/drawImage under-the-hood)
// NOTE: This method does not populate internal data structure that represents drawn signature. Thus, after using #fromDataURL, #toData won't work properly.
signaturePad.fromDataURL("data:image/png;base64,iVBORw0K...");

// Draws signature image from data URL and alters it with the given options
signaturePad.fromDataURL("data:image/png;base64,iVBORw0K...", { ratio: 1, width: 400, height: 200, xOffset: 100, yOffset: 50 });

// Returns signature image as an array of point groups
const data = signaturePad.toData();

// Draws signature image from an array of point groups
signaturePad.fromData(data);

// Draws signature image from an array of point groups, without clearing your existing image (clear defaults to true if not provided)
signaturePad.fromData(data, { clear: false });

// Clears the canvas
signaturePad.clear();

// Returns true if canvas is empty, otherwise returns false
signaturePad.isEmpty();

// Unbinds all event handlers
signaturePad.off();

// Rebinds all event handlers
signaturePad.on();

Options

dotSize

(float or function) Radius of a single dot.

minWidth

(float) Minimum width of a line. Defaults to 0.5.

maxWidth

(float) Maximum width of a line. Defaults to 2.5.

throttle

(integer) Draw the next point at most once per every x milliseconds. Set it to 0 to turn off throttling. Defaults to 16.

minDistance

(integer) Add the next point only if the previous one is farther than x pixels. Defaults to 5.

backgroundColor

(string) Color used to clear the background. Can be any color format accepted by context.fillStyle. Defaults to "rgba(0,0,0,0)" (transparent black). Use a non-transparent color e.g. "rgb(255,255,255)" (opaque white) if you'd like to save signatures as JPEG images.

penColor

(string) Color used to draw the lines. Can be any color format accepted by context.fillStyle. Defaults to "black".

velocityFilterWeight

(float) Weight used to modify new velocity based on the previous velocity. Defaults to 0.7.

You can set options during initialization:

const signaturePad = new SignaturePad(canvas, {
    minWidth: 5,
    maxWidth: 10,
    penColor: "rgb(66, 133, 244)"
});

or during runtime:

const signaturePad = new SignaturePad(canvas);
signaturePad.minWidth = 5;
signaturePad.maxWidth = 10;
signaturePad.penColor = "rgb(66, 133, 244)";

Events

beginStroke

Triggered before stroke begins.

endStroke

Triggered after stroke ends.

beforeUpdateStroke

Triggered before stroke update.

afterUpdateStroke

Triggered after stroke update.

You can add listeners to events with .addEventListener:

const signaturePad = new SignaturePad(canvas);
signaturePad.addEventListener("beginStroke", () => {
  console.log("Signature started");
}, { once: true });

Tips and tricks

Handling high DPI screens

To correctly handle canvas on low and high DPI screens one has to take devicePixelRatio into account and scale the canvas accordingly. This scaling is also necessary to properly display signatures loaded via SignaturePad#fromDataURL. Here's an example how it can be done:

function resizeCanvas() {
    const ratio =  Math.max(window.devicePixelRatio || 1, 1);
    canvas.width = canvas.offsetWidth * ratio;
    canvas.height = canvas.offsetHeight * ratio;
    canvas.getContext("2d").scale(ratio, ratio);
    signaturePad.clear(); // otherwise isEmpty() might return incorrect value
}

window.addEventListener("resize", resizeCanvas);
resizeCanvas();

Instead of resize event you can listen to screen orientation change, if you're using this library only on mobile devices. You can also throttle the resize event - you can find some examples on this MDN page.

When you modify width or height of a canvas, it will be automatically cleared by the browser. SignaturePad doesn't know about it by itself, so you can call signaturePad.fromData(signaturePad.toData()) to reset the drawing, or signaturePad.clear() to make sure that signaturePad.isEmpty() returns correct value in this case.

This clearing of the canvas by the browser can be annoying, especially on mobile devices e.g. when screen orientation is changed. There are a few workarounds though, e.g. you can lock screen orientation, or read an image from the canvas before resizing it and write the image back after.

Handling data URI encoded images on the server side

If you are not familiar with data URI scheme, you can read more about it on Wikipedia.

There are 2 ways you can handle data URI encoded images.

You could simply store it in your database as a string and display it in HTML like this:

<img src="data:image/png;base64,iVBORw0K..." />

but this way has many disadvantages - it's not easy to get image dimensions, you can't manipulate it e.g. to create a thumbnail and it also has some performance issues on mobile devices.

Thus, more common way is to decode it and store as a file. Here's an example in Ruby:

require "base64"

data_uri = "data:image/png;base64,iVBORw0K..."
encoded_image = data_uri.split(",")[1]
decoded_image = Base64.decode64(encoded_image)
File.open("signature.png", "wb") { |f| f.write(decoded_image) }

Here's an example in PHP:

$data_uri = "data:image/png;base64,iVBORw0K...";
$encoded_image = explode(",", $data_uri)[1];
$decoded_image = base64_decode($encoded_image);
file_put_contents("signature.png", $decoded_image);

Here's an example in C# for ASP.NET:

var dataUri = "data:image/png;base64,iVBORw0K...";
var encodedImage = dataUri.Split(',')[1];
var decodedImage = Convert.FromBase64String(encodedImage);
System.IO.File.WriteAllBytes("signature.png", decodedImage);

Removing empty space around a signature

If you'd like to remove (trim) empty space around a signature, you can do it on the server side or the client side. On the server side you can use e.g. ImageMagic and its trim option: convert -trim input.jpg output.jpg. If you don't have access to the server, or just want to trim the image before submitting it to the server, you can do it on the client side as well. There are a few examples how to do it, e.g. here or here and there's also a tiny library trim-canvas that provides this functionality.

Drawing over an image

Demo: https://jsfiddle.net/szimek/d6a78gwq/

Demo

Demo works in desktop and mobile browsers. You can check out its source code for some tips on how to handle window resize and high DPI screens. You can also find more about the latter in HTML5 Rocks tutorial.

Other demos

Download Details:

Author: Szimek
Source Code: https://github.com/szimek/signature_pad 
License: MIT license

#javascript #drawing #canvas #html5